home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / program / freeli22.zip / FREELIB1.ASX < prev    next >
Text File  |  1996-09-01  |  98KB  |  3,310 lines

  1. ~~~C_START
  2. Ideal
  3.  
  4. Extrn       main:near
  5. Public      startup, exit
  6. Public      TopByte, AtExitCnt
  7.  
  8. Model Tiny
  9. CodeSeg
  10. P186
  11.  
  12. ;****************** startup() -- Start program
  13.  
  14. Proc        startup
  15.  
  16.             mov cx,0121h            ;Check for 186+
  17.             shl ch,cl
  18.             jz p0_badcpu
  19.  
  20.             mov ax,3001h            ;Check for DOS 4.0
  21.             int 21h
  22.             cmp al,4
  23.             jb p0_baddos
  24.  
  25.             mov ah,4Ah              ;Modify memory allocation
  26.             mov bx,1000h            ;Keep first 64K
  27.             int 21h                 ;DOS call
  28.  
  29.             mov sp,0FF00h           ;Shift stack down 256 bytes
  30.  
  31.             mov ax,2523h            ;Set null Ctrl-C handler
  32.             mov dx,offset IntRet    ;so that Ctrl-C can't
  33.             int 21h                 ;abort the program
  34.  
  35.             mov ax,3500h            ;Get current Int 0 handler
  36.             int 21h                 ; (divide by zero)
  37.  
  38.             mov [word OldInt0],bx   ;Save handler
  39.             mov [word OldInt0+2],es
  40.  
  41.             push cs                 ;Restore ES
  42.             pop es
  43.  
  44.             mov ax,2500h            ;Set the divide by zero
  45.             mov dx,offset DivZero   ;handler: now it just
  46.             int 21h                 ;ignores the error
  47.  
  48.             mov ax,0FB00h           ;Initialize dynamic memory
  49.             sub ax,offset TopByte   ;leaving 768 bytes for the
  50.             mov [word TopByte],ax   ;stack (which is at 0FF00h)
  51.             mov [byte TopByte+2],2  ;Initial block is free, last
  52.  
  53.             mov di,sp               ;Parse arguments
  54.             call ParseArgs
  55.  
  56.             call main               ;Call main function
  57.  
  58.             push ax                 ;Terminate with return code
  59.             call exit
  60.  
  61. p0_baddos:  push offset BadDosStr   ;'Bad Dos' message
  62.             jmp p0_error
  63.  
  64. p0_badcpu:  push offset BadCPUStr   ;'Bad CPU' message
  65.  
  66. p0_error:   mov dx,offset BadStr    ;Print first part
  67.             mov ah,9
  68.             int 21h
  69.             pop dx                  ;Print second part
  70.             int 21h
  71.             mov ax,4CFFh            ;Return with error 255
  72.             int 21h
  73.  
  74. EndP        startup
  75.  
  76. ;****************** DivZero -- Divide by zero handler
  77.  
  78. Proc        DivZero
  79.  
  80.             push bp                 ;Set up stack frame
  81.             mov bp,sp
  82.             pusha                   ;Save all registers
  83.             push ds
  84.  
  85.             xor cx,cx               ;CX = displacement
  86.  
  87.             mov ds,[bp+4]           ;DS:BX = DIV instruction
  88.             mov bx,[bp+2]
  89.             mov al,[bx+1]           ;AL = AH = ModRM byte
  90.             mov ah,al
  91.  
  92.             and al,0C0h             ;Mask off mode bits
  93.             cmp al,0C0h             ;Mode = 11 (no disp)?
  94.             je DZ_dis0
  95.             cmp al,040h             ;Mode = 01 (1 byte disp)?
  96.             je DZ_dis1
  97.             cmp al,080h             ;Mode = 10 (2 byte disp)?
  98.             je DZ_dis2
  99.             cmp ah,036h             ;Mode = 00.  No disp except
  100.             jne DZ_dis0             ;if R/M = 110 (2 byte disp).
  101.  
  102. DZ_dis2:    inc cx                  ;2 byte displacement
  103. DZ_dis1:    inc cx                  ;1 byte displacement
  104. DZ_dis0:    inc cx                  ;Instruction is two bytes
  105.             inc cx
  106.             add [bp+2],cx           ;Skip past instruction
  107.  
  108. DZ_done:    pop ds                  ;Restore registers
  109.             popa
  110.             pop bp                  ;Delete stack frame
  111. IntRet:     iret                    ;Interrupt return
  112.  
  113. EndP        DivZero
  114.  
  115. ;****************** Internal data
  116.  
  117. OldInt0:                            ;Old divide-by-zero handler
  118. BadStr      db 'Need at least $'    ;OK to overwrite strings
  119. BadCPUStr   db 'an 80186 CPU',13,10,'$'
  120. BadDosStr   db 'DOS 4.0',13,10,'$'
  121.  
  122. AtExitCnt   dw 0                    ;Exit function count
  123. AtExitTblO  equ 0FF60h              ;Exit function table offset
  124.  
  125. ;****************** exit() -- Terminate program
  126. ;void exit(int retval);
  127.  
  128. Proc        exit
  129.  
  130.             mov ax,2500h            ;Reset the default divide
  131.             mov dx,[word OldInt0]   ;by zero handler
  132.             mov ds,[word OldInt0+2]
  133.             int 21h
  134.  
  135.             push cs                 ;Restore DS
  136.             pop ds
  137.  
  138.             mov cx,[AtExitCnt]      ;CX = atexit count
  139.             jcxz p1_done            ;No exit functions?
  140.             mov si,AtExitTblO       ;SI = atexit table
  141.  
  142. p1_loop:    lodsw                   ;Get function
  143.             call ax                 ;Call function
  144.             loop p1_loop            ;Loop back
  145.  
  146. p1_done:    pop ax ax               ;Pop arg into AX
  147.             mov ah,4Ch              ;Terminate program
  148.             int 21h                 ;DOS call
  149.  
  150. EndP        exit
  151.  
  152. ;**************************** ParseArgs() -- internal: Parse arguments
  153.  
  154. Proc        ParseArgs
  155.             ;Supply DI = 256-byte buffer, CS = DS = ES
  156.             ;Returns CX = number of arguments
  157.             ;the buffer will contain a list of
  158.             ;near offsets to AsciiZ strings
  159.             ;(and the strings themselves)
  160.  
  161.             pusha                   ;Save all registers
  162.  
  163.             mov bx,di               ;BX = buffer
  164.             mov cl,[80h]            ;CX = length of command line
  165.             xor ch,ch               ;which is stored at 80h
  166.  
  167.             push cx                 ;Save CX
  168.             mov si,81h              ;SI = command line
  169.             add di,80h              ;DI = second half of buffer
  170.             push di                 ;Save DI
  171.             rep movsb               ;Move command line out of DTA
  172.             xor al,al               ;Replace the CR at the end
  173.             stosb                   ;with a null
  174.             pop di cx               ;Restore DI, length in CX
  175.             inc cx                  ;Make length include last null
  176.             xor dx,dx               ;Zero argument counter
  177.             mov al,' '              ;AL = space
  178.  
  179. p2_loop:    repe scasb              ;Search for a non-space
  180.             dec di
  181.             inc cx
  182.             cmp [byte di],0         ;Is it a null?
  183.             je p2_done
  184.             mov [bx],di             ;Store offset in list
  185.             inc bx                  ;Advance pointers
  186.             inc bx
  187.             inc dx
  188.             repne scasb             ;Search for a space
  189.             mov [byte di-1],0       ;Replace it by a null
  190.             jmp p2_loop             ;Loop back
  191.  
  192. p2_done:    mov bp,sp               ;Change pushed CX
  193.             mov [bp+12],dx
  194.             popa                    ;Restore registers
  195.             ret                     ;Return
  196.  
  197. EndP        ParseArgs
  198.  
  199. UDataSeg                            ;Uninit. data seg: dummy
  200.  
  201. Label       TopByte                 ;Top byte of code (start of heap)
  202.  
  203. End
  204.  
  205. ~~~C_ATEXIT
  206. Ideal
  207.  
  208. Extrn       AtExitCnt:word
  209. Public      atexit
  210.  
  211. Model Tiny
  212. CodeSeg
  213. P186
  214.  
  215. AtExitTblO  equ 0FF60h              ;Exit function table offset
  216.  
  217. ;****************** atexit() -- Add exit function
  218. ;int atexit(void *func);
  219.  
  220. func        equ bp+4
  221.  
  222. Proc        atexit
  223.  
  224.             push bp                 ;Set up stack frame
  225.             mov bp,sp
  226.             push bx                 ;Save BX
  227.  
  228.             cmp [word AtExitCnt],16 ;16 functions max
  229.             jae p1_error
  230.  
  231.             mov bx,[AtExitCnt]      ;BX = offset
  232.             add bx,bx
  233.             mov ax,[func]           ;AX = function
  234.             mov [AtExitTblO+bx],ax  ;Add function to table
  235.             inc [word AtExitCnt]    ;Increment count
  236.  
  237. p1_done:    pop bx                  ;Restore BX
  238.             pop bp                  ;Delete stack frame
  239.             ret 2                   ;Return
  240.  
  241. p1_error:   xor ax,ax               ;Return 0: failure
  242.             jmp p1_done
  243.  
  244. EndP        atexit
  245.  
  246. End
  247.  
  248. ~~~C_PUTCHR
  249. Ideal
  250.  
  251. Public      PUT_CHAR
  252.  
  253. Model Tiny
  254. CodeSeg
  255. P186
  256.  
  257. ;****************** PUT_CHAR -- Like Int 29h but with redirection.
  258. ;                               Takes AL = char.
  259.  
  260. Proc        PUT_CHAR
  261.  
  262.             pusha                   ;Save registers
  263.             xchg dx,ax              ;STDOUT output, DL = char
  264.             mov ah,2
  265.             int 21h                 ;DOS call
  266.             popa                    ;Restore registers
  267.             ret                     ;Return
  268.  
  269. EndP        PUT_CHAR
  270.  
  271. End
  272.  
  273. ~~~C_FILES
  274. Ideal
  275.  
  276. Public      fopen,fclose,fsetbuf
  277.  
  278. Model Tiny
  279. CodeSeg
  280. P186
  281.  
  282. ;****************** File Structure . . .
  283.  
  284. ;                   Offset  Size    Description
  285.  
  286. ;                     0     Word    File handle
  287. ;                     2     Byte    File mode
  288. ;                     3     Byte    Modify flag
  289. ;                     4     Dword   Buffer position in file
  290. ;                     8     Word    Buffer pointer position
  291. ;                     10    Word    Number of bytes in buffer
  292. ;                     12    Word    Size of buffer (N)
  293. ;                     14    Word    Signature 'FI'
  294. ;                     16    N bytes File buffer
  295.  
  296. BUF_SIZ     dw 1024                 ;Buffer size (default 1K)
  297.  
  298. F_MODES     db 00h,01h              ;0 = open for read
  299.             db 02h,11h              ;1 = open/create for read/write
  300.             db 02h,01h              ;2 = open for read/write
  301.             db 02h,12h              ;3 = create/truncate for read/write
  302.             db 02h,10h              ;4 = create for read/write
  303.             db 6 dup(0)             ;Fail for 5, 6, 7
  304.  
  305. ;****************** fopen() -- Open a buffered file
  306. ;int fopen(char *fname, int mode);
  307.  
  308. fname       = bp+6
  309. mode        = bp+4
  310.  
  311. Proc        fopen
  312.  
  313.             push bp                 ;Set up stack frame
  314.             mov bp,sp
  315.             push ds                 ;Save registers
  316.             pusha
  317.  
  318.             mov bx,[mode]           ;BX = mode
  319.             and bx,7                ;Mode mod 8
  320.             add bx,bx
  321.             mov dl,[F_MODES+bx+1]   ;BX:DX = DOS mode
  322.             mov bl,[F_MODES+bx]
  323.             xor dh,dh
  324.             xor bh,bh
  325.  
  326.             mov ax,6C00h            ;Extended open file
  327.             xor cx,cx               ;Normal attribute
  328.             mov si,[fname]          ;SI = name
  329.             int 21h                 ;DOS call
  330.             jc p1_err1              ;Check for errors
  331.  
  332.             xchg dx,ax              ;DX = handle
  333.  
  334.             mov ah,48h              ;Allocate memory
  335.             mov bx,[BUF_SIZ]        ;BX = num. of paras
  336.             shr bx,4                ; = (BUF_SIZ / 16) + 1
  337.             inc bx
  338.             int 21h                 ;DOS call
  339.             jc p1_err2              ;Check for errors
  340.  
  341.             mov ds,ax               ;DS = segment
  342.             mov [word 0],dx         ;[word 0] = handle
  343.             mov cx,[mode]
  344.             mov [word 2],cx         ;[word 2] = mode
  345.             xor bx,bx
  346.             mov [word 4],bx         ;[dword 4] = buffer position
  347.             mov [word 6],bx
  348.             mov [word 8],bx         ;[word 8] = buffer pointer
  349.             mov bx,[cs:BUF_SIZ]
  350.             mov [word 12],bx        ;[word 12] = buffer size
  351.             mov [word 14],'FI'      ;[word 14] = 'FI': signature
  352.  
  353.             mov bx,dx               ;BX = handle
  354.             mov ah,3Fh              ;Read file
  355.             mov cx,[cs:BUF_SIZ]     ;BUF_SIZ bytes
  356.             mov dx,16               ;Buffer offset
  357.             int 21h                 ;DOS call
  358.  
  359.             mov [word 10],ax        ;Set byte count
  360.  
  361. p1_done:    popa                    ;Restore registers
  362.             mov ax,ds               ;Result in AX
  363.             pop ds
  364.             pop bp                  ;Delete stack frame
  365.             ret 4                   ;Return
  366.  
  367. p1_err2:    mov ah,3Eh              ;Out of memory, close file
  368.             mov bx,dx               ;BX = handle
  369.             int 21h                 ;DOS call
  370.  
  371. p1_err1:    push 0                  ;Error, return 0
  372.             pop ds
  373.             jmp p1_done
  374.  
  375. EndP        fopen
  376.  
  377. ;****************** fclose() -- Close a buffered file
  378. ;void fclose(int fptr);
  379.  
  380. fptr        = bp+4
  381.  
  382. Proc        fclose
  383.  
  384.             push bp                 ;Set up stack frame
  385.             mov bp,sp
  386.             push ds es              ;Save registers
  387.             pusha
  388.  
  389.             mov ds,[fptr]           ;DS = seg of file
  390.             cmp [word 14],'FI'      ;Check for signature
  391.             jne p2_done
  392.  
  393.             mov bx,[word 0]         ;BX = handle
  394.  
  395.             cmp [byte 2],0          ;Read only, can't write buffer
  396.             je p2_skip
  397.  
  398.             mov ax,4200h            ;Move file ptr
  399.             mov cx,[word 6]         ;CX:DX = buffer pos
  400.             mov dx,[word 4]
  401.             int 21h                 ;DOS call
  402.  
  403.             mov ah,40h              ;Write file
  404.             mov cx,[word 10]        ;CX = bytes
  405.             mov dx,16               ;Buffer offset
  406.             int 21h                 ;DOS call
  407.  
  408. p2_skip:    mov ah,3Eh              ;Close file
  409.             int 21h                 ;DOS call
  410.  
  411.             mov ah,49h              ;Free memory
  412.             push ds                 ;ES = segment
  413.             pop es
  414.             int 21h                 ;DOS call
  415.  
  416. p2_done:    popa                    ;Restore registers
  417.             pop es ds
  418.             pop bp                  ;Delete stack frame
  419.             ret 2                   ;Return
  420.  
  421. EndP        fclose
  422.  
  423. ;****************** fsetbuf() -- Set buffer size (for future use)
  424. ;int fsetbuf(int bsize);
  425.  
  426. bsize       = bp+4
  427.  
  428. Proc        fsetbuf
  429.  
  430.             push bp                 ;Set up stack frame
  431.             mov bp,sp
  432.  
  433.             mov ax,[bsize]          ;AX = size
  434.             and ax,7FF0h            ;Put it in range
  435.             cmp ax,128
  436.             jb $+5
  437.             mov ax,128
  438.             mov [BUF_SIZ],ax        ;Set buffer size
  439.  
  440.             pop bp                  ;Delete stack frame
  441.             ret 2                   ;Return
  442.  
  443. EndP        fsetbuf
  444.  
  445. End
  446.  
  447. ~~~C_FPUTC
  448. Ideal
  449.  
  450. Public      fputc
  451.  
  452. Model Tiny
  453. CodeSeg
  454. P186
  455.  
  456. ;****************** fputc() -- Put char to buffered file
  457. ;int fputc(int fptr, int chr);
  458.  
  459. fptr        = bp+6
  460. chr         = bp+4
  461.  
  462. Proc        fputc
  463.  
  464.             push bp                 ;Set up stack frame
  465.             mov bp,sp
  466.             push ds si bx cx dx     ;Save registers
  467.  
  468.             mov ds,[fptr]           ;DS = seg of file
  469.             cmp [word 14],'FI'      ;Check for signature
  470.             jne p1_error
  471.  
  472.             mov bx,[word 0]         ;BX = handle
  473.  
  474.             cmp [byte 2],0          ;Read only, can't put char
  475.             je p1_error
  476.  
  477.             mov si,[word 8]         ;SI = pointer pos
  478.             cmp si,[word 12]        ;Filled buffer?
  479.             jb p1_write             ;Jump if not
  480.  
  481.             mov ax,4200h            ;Move file ptr
  482.             mov cx,[word 6]         ;CX:DX = buffer pos
  483.             mov dx,[word 4]
  484.             int 21h                 ;DOS call
  485.  
  486.             mov ah,40h              ;Write file
  487.             mov cx,[word 12]        ;CX = bytes
  488.             mov dx,16               ;Buffer offset
  489.             int 21h                 ;DOS call
  490.  
  491.             mov ah,3Fh              ;Read file, same size
  492.             int 21h                 ;DOS call
  493.             mov [word 10],ax        ;Set byte count
  494.  
  495.             xor si,si
  496.             add [word 4],cx         ;Advance buffer position
  497.             adc [word 6],si
  498.             mov [word 8],si         ;Pointer pos = 0
  499.  
  500. p1_write:   mov al,[chr]            ;AX = char
  501.             xor ah,ah
  502.             mov [16+si],al          ;Put char in buffer
  503.             inc si                  ;Advance pointer
  504.             mov [word 8],si
  505.             cmp si,[word 10]        ;Hit last byte?
  506.             jna p1_done
  507.  
  508.             inc [word 10]           ;Advance byte count
  509.             mov [byte 3],1          ;Set modify flag
  510.  
  511. p1_done:    pop dx cx bx si ds      ;Restore registers
  512.             pop bp                  ;Delete stack frame
  513.             ret 4                   ;Return
  514.  
  515. p1_error:   mov ax,-1               ;Error, return EOF
  516.             jmp p1_done
  517.  
  518. EndP        fputc
  519.  
  520. End
  521.  
  522. ~~~C_FGETC
  523. Ideal
  524.  
  525. Public      fgetc
  526.  
  527. Model Tiny
  528. CodeSeg
  529. P186
  530.  
  531. ;****************** fgetc() -- Get char from buffered file
  532. ;int fgetc(int fptr);
  533.  
  534. fptr        = bp+4
  535.  
  536. Proc        fgetc
  537.  
  538.             push bp                 ;Set up stack frame
  539.             mov bp,sp
  540.             push ds si bx cx dx     ;Save registers
  541.  
  542.             mov ds,[fptr]           ;DS = seg of file
  543.             cmp [word 14],'FI'      ;Check for signature
  544.             jne p1_error
  545.  
  546.             mov bx,[word 0]         ;BX = handle
  547.  
  548.             mov si,[word 8]         ;SI = pointer pos
  549.             mov cx,[word 12]        ;CX = buffer size
  550.             cmp si,cx               ;End of buffer?
  551.             jb p1_read              ;Jump if not
  552.  
  553.             cmp [byte 3],0          ;Modified?
  554.             je p1_skip1
  555.  
  556.             mov [byte 3],0          ;Clear modify flag
  557.  
  558.             mov ax,4200h            ;Move file ptr
  559.             mov cx,[word 6]         ;CX:DX = buffer pos
  560.             mov dx,[word 4]
  561.             int 21h                 ;DOS call
  562.  
  563.             mov ah,40h              ;Write file
  564.             mov cx,[word 12]        ;CX = bytes
  565.             mov dx,16               ;Buffer offset
  566.             int 21h                 ;DOS call
  567.  
  568. p1_skip1:   xor si,si
  569.             add [word 4],cx         ;Advance buffer position
  570.             adc [word 6],si
  571.  
  572.             mov ah,3Fh              ;Read file
  573.             mov cx,[word 12]        ;CX = bytes
  574.             mov dx,16               ;Buffer offset
  575.             int 21h                 ;DOS call
  576.             mov [word 10],ax        ;Set byte count
  577.  
  578. p1_read:    cmp si,[word 10]        ;Hit last byte?
  579.             jae p1_error
  580.  
  581.             mov al,[16+si]          ;Get char from buffer
  582.             xor ah,ah
  583.             inc si                  ;Advance pointer
  584.             mov [word 8],si
  585.  
  586. p1_done:    pop dx cx bx si ds      ;Restore registers
  587.             pop bp                  ;Delete stack frame
  588.             ret 2                   ;Return
  589.  
  590. p1_error:   mov ax,-1               ;Error, return EOF
  591.             jmp p1_done
  592.  
  593. EndP        fgetc
  594.  
  595. End
  596.  
  597. ~~~C_FSEEK
  598. Ideal
  599.  
  600. Public      fseek,ftell
  601.  
  602. Model Tiny
  603. CodeSeg
  604. P186
  605.  
  606. ;****************** fseek() -- Seek to position in buffered file
  607. ;int fseek(int fptr, long pos, int cmd);
  608.  
  609. fptr        = bp+10
  610. pos         = bp+6
  611. cmd         = bp+4
  612.  
  613. Proc        fseek
  614.  
  615.             push bp                 ;Set up stack frame
  616.             mov bp,sp
  617.             push ds bx cx dx        ;Save registers
  618.  
  619.             mov ds,[fptr]           ;DS = seg of file
  620.             cmp [word 14],'FI'      ;Check for signature
  621.             jne p1_error
  622.  
  623.             mov bx,[word 0]         ;BX = handle
  624.  
  625.             cmp [byte 2],0          ;Read only, can't write buffer
  626.             je p1_seek
  627.  
  628.             mov ax,4200h            ;Move file ptr
  629.             mov cx,[word 6]         ;CX:DX = buffer pos
  630.             mov dx,[word 4]
  631.             int 21h                 ;DOS call
  632.  
  633.             mov ah,40h              ;Write file
  634.             mov cx,[word 10]        ;CX = bytes
  635.             mov dx,16               ;Buffer offset
  636.             int 21h                 ;DOS call
  637.  
  638. p1_seek:    mov ax,4200h            ;Move file ptr
  639.             mov cx,[word 6]         ;CX:DX = current pos
  640.             mov dx,[word 4]         ; = buffer pos + pointer
  641.             add dx,[word 8]
  642.             adc cx,0
  643.             int 21h                 ;DOS call
  644.  
  645.             mov ah,42h              ;Move file ptr
  646.             mov al,[cmd]            ;AL = command
  647.             mov cx,[pos+2]          ;CX:DX = new pos
  648.             mov dx,[pos]
  649.             int 21h                 ;DOS call
  650.  
  651.             mov [word 6],dx         ;Save position
  652.             mov [word 4],ax
  653.  
  654.             mov ah,3Fh              ;Read file
  655.             mov cx,[word 12]        ;CX = bytes
  656.             mov dx,16               ;Buffer offset
  657.             int 21h                 ;DOS call
  658.  
  659.             mov [word 10],ax        ;Set byte count
  660.             mov [word 8],0          ;Pointer = 0
  661.             mov ax,1                ;return 1: success
  662.  
  663. p1_done:    pop dx cx bx ds         ;Restore registers
  664.             pop bp                  ;Delete stack frame
  665.             ret 8                   ;Return
  666.  
  667. p1_error:   xor ax,ax               ;Error, return 0
  668.             jmp p1_done
  669.  
  670. EndP        fseek
  671.  
  672. ;****************** ftell() -- Return pointer in buffered file
  673. ;long ftell(int fptr);
  674.  
  675. fptr        = bp+4
  676.  
  677. Proc        ftell
  678.  
  679.             push bp                 ;Set up stack frame
  680.             mov bp,sp
  681.             push ds                 ;Save registers
  682.  
  683.             mov ds,[fptr]           ;DS = seg of file
  684.             cmp [word 14],'FI'      ;Check for signature
  685.             jne p2_error
  686.  
  687.             mov dx,[word 6]         ;DX:AX = current pos
  688.             mov ax,[word 4]         ; = buffer pos + pointer
  689.             add ax,[word 8]
  690.             adc dx,0
  691.  
  692. p2_done:    pop ds                  ;Restore registers
  693.             pop bp                  ;Delete stack frame
  694.             ret 2                   ;Return
  695.  
  696. p2_error:   xor ax,ax               ;Error, return 0
  697.             xor dx,dx
  698.             jmp p2_done
  699.  
  700. EndP        ftell
  701.  
  702. End
  703.  
  704. ~~~C_FREAD
  705. Ideal
  706.  
  707. Extrn       fgetc:near
  708. Public      fread
  709.  
  710. Model Tiny
  711. CodeSeg
  712. P186
  713.  
  714. ;****************** fread() -- Read block from buffered file
  715. ;int fread(int fptr, int nbytes, void *buf);
  716.  
  717. fptr        = bp+8
  718. nbytes      = bp+6
  719. buf         = bp+4
  720.  
  721. Proc        fread
  722.  
  723.             push bp                 ;Set up stack frame
  724.             mov bp,sp
  725.             push bx cx di           ;Save registers
  726.  
  727.             mov bx,[fptr]           ;BX = file ptr
  728.             mov cx,[nbytes]         ;CX = num. of bytes
  729.             mov di,[buf]            ;DI = buffer ptr
  730.             jcxz p1_done            ;Zero bytes, do nothing
  731.  
  732. p1_loop:    push bx                 ;Get char
  733.             call fgetc
  734.             test ax,ax              ;Check for errors
  735.             jl p1_done
  736.             mov [di],al             ;Store byte
  737.             inc di
  738.             loop p1_loop            ;Loop back
  739.  
  740. p1_done:    sub di,[buf]            ;AX = byte count
  741.             xchg ax,di
  742.  
  743.             pop di cx bx            ;Restore registers
  744.             pop bp                  ;Delete stack frame
  745.             ret 6                   ;Return
  746.  
  747. EndP        fread
  748.  
  749. End
  750.  
  751. ~~~C_FWRITE
  752. Ideal
  753.  
  754. Extrn       fputc:near
  755. Public      fwrite
  756.  
  757. Model Tiny
  758. CodeSeg
  759. P186
  760.  
  761. ;****************** fwrite() -- Write block to buffered file
  762. ;int fwrite(int fptr, int nbytes, void *buf);
  763.  
  764. fptr        = bp+8
  765. nbytes      = bp+6
  766. buf         = bp+4
  767.  
  768. Proc        fwrite
  769.  
  770.             push bp                 ;Set up stack frame
  771.             mov bp,sp
  772.             push bx cx si           ;Save registers
  773.  
  774.             mov bx,[fptr]           ;BX = file ptr
  775.             mov cx,[nbytes]         ;CX = num. of bytes
  776.             mov si,[buf]            ;SI = buffer ptr
  777.             xor ax,ax               ;Fixup for zero check
  778.             jcxz p1_done            ;Zero bytes, do nothing
  779.  
  780. p1_loop:    lodsb                   ;Load byte
  781.             push bx ax              ;Write char
  782.             call fputc
  783.             test ax,ax              ;Check for errors
  784.             jl p1_done
  785.             loop p1_loop            ;Loop back
  786.  
  787. p1_done:    sub si,[buf]            ;AX = byte count
  788.             add ax,1                ;Subtract 1 if error
  789.             sbb si,0
  790.             xchg ax,si
  791.  
  792.             pop si cx bx            ;Restore registers
  793.             pop bp                  ;Delete stack frame
  794.             ret 6                   ;Return
  795.  
  796. EndP        fwrite
  797.  
  798. End
  799.  
  800. ~~~C_FTRUNC
  801. Ideal
  802.  
  803. Public      ftrunc
  804.  
  805. Model Tiny
  806. CodeSeg
  807. P186
  808.  
  809. ;****************** ftrunc() -- Truncate buffered file at current position
  810. ;int ftrunc(int fptr);
  811.  
  812. fptr        = bp+4
  813.  
  814. Proc        ftrunc
  815.  
  816.             push bp                 ;Set up stack frame
  817.             mov bp,sp
  818.             push ds bx cx dx        ;Save registers
  819.  
  820.             mov ds,[fptr]           ;DS = seg of file
  821.             cmp [word 14],'FI'      ;Check for signature
  822.             jne p1_error
  823.  
  824.             cmp [byte 2],0          ;Read only, can't truncate
  825.             je p1_error
  826.  
  827.             mov bx,[word 0]         ;BX = handle
  828.  
  829.             mov ax,4200h            ;Move file ptr
  830.             mov cx,[word 6]         ;CX:DX = current pos
  831.             mov dx,[word 4]         ; = buffer pos + pointer
  832.             add dx,[word 8]
  833.             adc cx,0
  834.             int 21h                 ;DOS call
  835.  
  836.             mov ah,40h              ;Write 0 bytes to file
  837.             xor cx,cx               ;this truncates the file
  838.             int 21h
  839.  
  840.             mov [byte 3],1          ;Set modify flag
  841.             mov ax,[word 8]         ;Now, byte count = pointer + 1
  842.             inc ax
  843.             mov [word 10],ax
  844.             mov ax,1                ;return 1: success
  845.  
  846. p1_done:    pop dx cx bx ds         ;Restore registers
  847.             pop bp                  ;Delete stack frame
  848.             ret 2                   ;Return
  849.  
  850. p1_error:   xor ax,ax               ;Error, return 0
  851.             jmp p1_done
  852.  
  853. EndP        ftrunc
  854.  
  855. End
  856.  
  857. ~~~C_DELMOV
  858. Ideal
  859.  
  860. Public      fdel,fmove
  861.  
  862. Model Tiny
  863. CodeSeg
  864. P186
  865.  
  866. ;****************** fdel() -- Delete a file
  867. ;int fdel(char *strp);
  868.  
  869. strp        equ bp+4
  870.  
  871. Proc        fdel
  872.  
  873.             push bp                 ;Set up stack frame
  874.             mov bp,sp
  875.             push dx                 ;Save DX
  876.  
  877.             mov ah,41h              ;Delete file
  878.             mov dx,[strp]           ;DX = string pointer
  879.             int 21h                 ;DOS call
  880.  
  881.             sbb ax,ax               ;AX = 1 if ok, 0 if error
  882.             inc ax
  883.  
  884.             pop dx                  ;Restore DX
  885.             pop bp                  ;Delete stack frame
  886.             ret 2                   ;Return
  887.  
  888. EndP        fdel
  889.  
  890. ;****************** fmove() -- Move and/or rename a file
  891. ;int fmove(char *str1, char *str2);
  892.  
  893. str1        equ bp+6
  894. str2        equ bp+4
  895.  
  896. Proc        fmove
  897.  
  898.             push bp                 ;Set up stack frame
  899.             mov bp,sp
  900.             push es dx di           ;Save registers
  901.  
  902.             mov ah,56h              ;Move file
  903.             mov dx,[str1]           ;DX = old name
  904.             push ds                 ;ES = DS
  905.             pop es
  906.             mov di,[str2]           ;ES:DI = new name
  907.             int 21h                 ;DOS call
  908.  
  909.             sbb ax,ax               ;AX = 1 if ok, 0 if error
  910.             inc ax
  911.  
  912.             pop di dx es            ;Restore registers
  913.             pop bp                  ;Delete stack frame
  914.             ret 4                   ;Return
  915.  
  916. EndP        fmove
  917.  
  918. End
  919.  
  920. ~~~C_DIRECT
  921. Ideal
  922.  
  923. Public      getdir,setdir,mkdir,rmdir
  924.  
  925. Model Tiny
  926. CodeSeg
  927. P186
  928.  
  929. ;****************** getdir() -- Get current directory
  930. ;void getdir(char *strp);
  931.  
  932. strp        equ bp+4
  933.  
  934. Proc        getdir
  935.  
  936.             push bp                 ;Set up stack frame
  937.             mov bp,sp
  938.             pusha                   ;Save registers
  939.  
  940.             mov ah,19h              ;Get current drive
  941.             int 21h                 ;DOS call
  942.  
  943.             mov dl,al               ;DL = drive
  944.             mov ah,47h              ;Get current directory
  945.             mov si,[strp]           ;SI = string pointer
  946.             mov [byte si],'\'       ;Add leading slash
  947.             inc si
  948.             int 21h                 ;DOS call
  949.  
  950.             popa                    ;Restore registers
  951.             pop bp                  ;Delete stack frame
  952.             ret 2                   ;Return
  953.  
  954. EndP        getdir
  955.  
  956. ;****************** DIRcall -- Internal: used by setdir,mkdir,rmdir
  957. ;void DIRcall(void);
  958.  
  959. strp        equ bp+4
  960.  
  961. Proc        DIRcall
  962.  
  963.             push dx                 ;Save DX
  964.             mov dx,[strp]           ;DX = string pointer
  965.             int 21h                 ;DOS call
  966.  
  967.             sbb ax,ax               ;AX = 1 if ok, 0 if error
  968.             inc ax
  969.  
  970.             pop dx                  ;Restore DX
  971.             ret                     ;Return
  972.  
  973. EndP        DIRcall
  974.  
  975. ;****************** setdir() -- Set current directory
  976. ;int setdir(char *strp);
  977.  
  978. strp        equ bp+4
  979.  
  980. Proc        setdir
  981.  
  982.             push bp                 ;Set up stack frame
  983.             mov bp,sp
  984.  
  985.             mov ah,3Bh              ;Set current directory
  986.             call DIRcall            ;Directory call
  987.  
  988.             pop bp                  ;Delete stack frame
  989.             ret 2                   ;Return
  990.  
  991. EndP        setdir
  992.  
  993. ;****************** mkdir() -- Create a directory
  994. ;int mkdir(char *strp);
  995.  
  996. strp        equ bp+4
  997.  
  998. Proc        mkdir
  999.  
  1000.             push bp                 ;Set up stack frame
  1001.             mov bp,sp
  1002.  
  1003.             mov ah,39h              ;Create directory
  1004.             call DIRcall            ;Directory call
  1005.  
  1006.             pop bp                  ;Delete stack frame
  1007.             ret 2                   ;Return
  1008.  
  1009. EndP        mkdir
  1010.  
  1011. ;****************** rmdir() -- Remove a directory
  1012. ;int rmdir(char *strp);
  1013.  
  1014. strp        equ bp+4
  1015.  
  1016. Proc        rmdir
  1017.  
  1018.             push bp                 ;Set up stack frame
  1019.             mov bp,sp
  1020.  
  1021.             mov ah,3Ah              ;Remove directory
  1022.             call DIRcall            ;Directory call
  1023.  
  1024.             pop bp                  ;Delete stack frame
  1025.             ret 2                   ;Return
  1026.  
  1027. EndP        rmdir
  1028.  
  1029. End
  1030.  
  1031. ~~~C_DRIVE
  1032. Ideal
  1033.  
  1034. Public      getdrive,setdrive
  1035.  
  1036. Model Tiny
  1037. CodeSeg
  1038. P186
  1039.  
  1040. ;****************** getdrive() -- Get current drive
  1041. ;int getdrive(void);
  1042.  
  1043. Proc        getdrive
  1044.  
  1045.             mov ah,19h              ;Get current drive
  1046.             int 21h
  1047.             xor ah,ah               ;Zero AH
  1048.             ret                     ;Return
  1049.  
  1050. EndP        getdrive
  1051.  
  1052. ;****************** setdrive() -- set current drive
  1053. ;void setdrive(int drnum);
  1054.  
  1055. drnum       equ bp+4
  1056.  
  1057. Proc        setdrive
  1058.  
  1059.             push bp                 ;Set up stack frame
  1060.             mov bp,sp
  1061.             pusha                   ;Save registers
  1062.  
  1063.             mov ah,0Eh              ;Set current drive
  1064.             mov dl,[drnum]          ;DL = drive number
  1065.             int 21h
  1066.  
  1067.             popa                    ;Restore registers
  1068.             pop bp                  ;Delete stack frame
  1069.             ret 2                   ;Return
  1070.  
  1071. EndP        setdrive
  1072.  
  1073. End
  1074.  
  1075. ~~~C_DFREE
  1076. Ideal
  1077.  
  1078. Public      getdfree
  1079.  
  1080. Model Tiny
  1081. CodeSeg
  1082. P186
  1083.  
  1084. ;****************** getdfree() -- Return amount of free disk space
  1085. ;long getdfree(int drive);
  1086.  
  1087. drive       equ bp+4
  1088.  
  1089. Proc        getdfree
  1090.  
  1091.             push bp                 ;Set up stack frame
  1092.             mov bp,sp
  1093.             push bx cx              ;Save registers
  1094.  
  1095.             mov dl,[drive]          ;DL = drive
  1096.             mov ah,36h              ;Get free disk space
  1097.             int 21h
  1098.  
  1099.             cwd                     ;DX:AX = AX
  1100.             cmp ax,-1               ;Invalid, return -1
  1101.             je p1_done
  1102.  
  1103.             mul cx                  ;DX:AX = free disk space
  1104.             mul bx                  ; = bytes/sector * sectors/a-unit
  1105.                                     ; * free a-units (allocation units)
  1106.  
  1107. p1_done:    pop cx bx               ;Restore registers
  1108.             pop bp                  ;Delete stack frame
  1109.             ret                     ;Return
  1110.  
  1111. EndP        getdfree
  1112.  
  1113. End
  1114.  
  1115. ~~~C_EXEC
  1116. Ideal
  1117.  
  1118. Extrn       allocmem:near,freemem:near
  1119. Public      exec
  1120.  
  1121. Model Tiny
  1122. CodeSeg
  1123. P186
  1124.  
  1125. ;****************** exec() -- Execute program
  1126. ;int exec(char *prog, char *cmdline);
  1127.  
  1128. prog        equ bp+6
  1129. cmdline     equ bp+4
  1130.  
  1131. Proc        exec
  1132.  
  1133.             push bp                 ;Set up stack frame
  1134.             mov bp,sp
  1135.             pusha                   ;Save all registers
  1136.             push ds es
  1137.  
  1138.             push 128                ;Allocate memory for
  1139.             call allocmem           ;the cmdline buffer
  1140.             test ax,ax              ;Out of memory?
  1141.             je p1_done
  1142.             xchg bx,ax              ;Pointer in BX
  1143.  
  1144.             mov si,[prog]           ;SI = program specification
  1145.  
  1146. p1_loop1:   lodsb                   ;Skip past initial spaces
  1147.             cmp al,' '
  1148.             je p1_loop1
  1149.             dec si
  1150.             push si                 ;Save prog string offset
  1151.  
  1152.             mov si,[cmdline]        ;SI = command line
  1153.             mov di,bx               ;DI = string buffer
  1154.             inc di
  1155.             mov cx,126              ;CX = 126
  1156.  
  1157. p1_loop3:   lodsb                   ;Copy the string and
  1158.             test al,al              ;count the chars
  1159.             je p1_cont
  1160.             stosb
  1161.             loop p1_loop3
  1162.  
  1163. p1_cont:    neg cx                  ;CX = char count
  1164.             add cx,126
  1165.             mov [bx],cl             ;Store count
  1166.             mov al,13               ;Store a CR
  1167.             stosb
  1168.  
  1169.             mov ax,[2Eh]            ;word 0 = environment
  1170.             mov [ParBlock],ax
  1171.             mov [ParBlock+2],bx     ;word 2 = command line
  1172.             mov [ParBlock+4],cs     ;word 4 = CS
  1173.             mov [ParBlock+6],5Ch    ;word 6 = 5Ch
  1174.             mov [ParBlock+8],cs     ;word 8 = CS
  1175.             mov [ParBlock+10],6Ch   ;word 10 = 6Ch
  1176.             mov [ParBlock+12],cs    ;word 12 = CS
  1177.  
  1178.             push bx                 ;Save memory pointer
  1179.  
  1180.             push ds                 ;ES:BX = parameter block
  1181.             pop es
  1182.             mov bx,offset ParBlock
  1183.             pop dx                  ;DX = program specification
  1184.             mov ax,4B00h            ;DOS EXEC function
  1185.  
  1186.             mov [StackBuf],ss       ;Save stack pointer
  1187.             mov [StackBuf+2],sp
  1188.  
  1189.             int 21h                 ;Execute program
  1190.  
  1191.             mov ss,[cs:StackBuf]    ;Restore stack pointer
  1192.             mov sp,[cs:StackBuf+2]
  1193.  
  1194.             sbb ax,ax               ;AX = 1 if ok, 0 if error
  1195.             inc ax
  1196.  
  1197.             call freemem            ;Free the memory (BX is still pushed)
  1198.  
  1199. p1_done:    mov [bp-2],ax           ;Change pushed AX
  1200.             pop es ds               ;Restore registers
  1201.             popa
  1202.             pop bp                  ;Delete stack frame
  1203.             ret 4                   ;Return
  1204.  
  1205. StackBuf    dw 0,0                  ;Save area for SS:SP
  1206.  
  1207. ParBlock    dw 7 dup(0)             ;EXEC parameter block
  1208.  
  1209. EndP        exec
  1210.  
  1211. End
  1212.  
  1213. ~~~C_BITIO
  1214. Ideal
  1215.  
  1216. Extrn       fopen:near,fclose:near,fgetc:near,fputc:near
  1217. Public      bfopen, bfclose, putbit, getbit
  1218. Public      putbits, getbits, putcode, getcode
  1219.  
  1220. Model Tiny
  1221. P186
  1222. CodeSeg
  1223.  
  1224. ;****************** Bit-File Structure . . .
  1225.  
  1226. ;                   Offset  Size    Description
  1227.  
  1228. ;                     0     Word    File handle
  1229. ;                     2     Word    File mode
  1230. ;                     4     Byte    Bit buffer
  1231. ;                     5     Byte    Bit mask
  1232.  
  1233. ;****************** bfopen() -- Open bit-file (returns bit handle)
  1234. ;                               Modes: 0 = read, 1 = write
  1235. ;int bfopen(char *fname, int mode);
  1236.  
  1237. fname       equ bp+6
  1238. mode        equ bp+4
  1239.  
  1240. Proc        bfopen
  1241.  
  1242.             push bp                 ;Set up stack frame
  1243.             mov bp,sp
  1244.             push ds bx cx dx        ;Save registers
  1245.  
  1246.             mov bx,[mode]           ;BX = mode
  1247.             and bx,1
  1248.             mov cx,bx               ;Save mode
  1249.             imul bx,3               ;Mode for fopen()
  1250.  
  1251.             push [fname] bx         ;Open the file
  1252.             call fopen
  1253.             test ax,ax              ;Check for errors
  1254.             jz p1_err1
  1255.             xchg dx,ax              ;DX = file
  1256.  
  1257.             mov ah,48h              ;Allocate memory
  1258.             mov bx,1                ;16 bytes
  1259.             int 21h                 ;DOS call
  1260.             jc p1_err2              ;Check for errors
  1261.  
  1262.             mov ds,ax               ;DS = bit-file
  1263.             mov [0],dx              ;Set file handle...
  1264.             mov [2],cx              ;file mode...
  1265.             mov [word 4],8000h      ;buffer/mask...
  1266.  
  1267. p1_done:    pop dx cx bx ds         ;Restore registers
  1268.             pop bp                  ;Delete stack frame
  1269.             ret 4                   ;Return
  1270.  
  1271. p1_err2:    push dx                 ;Out of memory, close file
  1272.             call fclose
  1273.  
  1274. p1_err1:    xor ax,ax               ;Error, return 0
  1275.             jmp p1_done
  1276.  
  1277. EndP        bfopen
  1278.  
  1279. ;****************** bfclose() -- Close bit-file
  1280. ;void bfclose(int bfp);
  1281.  
  1282. bfp         equ bp+4
  1283.  
  1284. Proc        bfclose
  1285.  
  1286.             push bp                 ;Set up stack frame
  1287.             mov bp,sp
  1288.             pusha                   ;Save all registers
  1289.             push es
  1290.  
  1291.             mov es,[bfp]            ;ES = bit-file
  1292.  
  1293.             cmp [word es:2],1       ;Input file?
  1294.             jne p2_skip
  1295.             cmp [byte es:5],80h     ;Buffer empty?
  1296.             je p2_skip
  1297.  
  1298.             push [es:0] [es:4]      ;Flush buffer
  1299.             call fputc
  1300.  
  1301. p2_skip:    push [es:0]             ;Close file
  1302.             call fclose
  1303.             mov ah,49h              ;Free memory
  1304.             int 21h
  1305.  
  1306.             pop es                  ;Restore registers
  1307.             popa
  1308.             pop bp                  ;Delete stack frame
  1309.             ret 2                   ;Return
  1310.  
  1311. EndP        bfclose
  1312.  
  1313. ;****************** getbit() -- Get bit from bit-file
  1314. ;int getbit(int bfp);
  1315.  
  1316. bfp         equ bp+4
  1317.  
  1318. Proc        getbit
  1319.  
  1320.             push bp                 ;Set up stack frame
  1321.             mov bp,sp
  1322.             push es                 ;Save registers
  1323.  
  1324.             mov es,[bfp]            ;ES = bit-file
  1325.             cmp [word es:2],0       ;Output file, can't input
  1326.             jne p3_done
  1327.             cmp [byte es:5],80h     ;Buffer empty?
  1328.             jne p3_skip1
  1329.  
  1330.             push [es:0]             ;Get char
  1331.             call fgetc
  1332.             mov [es:4],al           ;Save char
  1333.  
  1334. p3_skip1:   mov al,[es:4]           ;Get bit
  1335.             and al,[es:5]
  1336.             ror [byte es:5],1       ;Move to next bit
  1337.  
  1338.             test al,al              ;AX = 1 if nonzero,
  1339.             jz $+4                  ;or 0 if zero
  1340.             mov al,1
  1341.             cbw
  1342.  
  1343. p3_done:    pop es                  ;Restore registers
  1344.             pop bp                  ;Delete stack frame
  1345.             ret 2                   ;Return
  1346.  
  1347. EndP        getbit
  1348.  
  1349. ;****************** putbit() -- Put bit to bit-file
  1350. ;void putbit(int bfp, int bit);
  1351.  
  1352. bfp         equ bp+6
  1353. bit         equ bp+4
  1354.  
  1355. Proc        putbit
  1356.  
  1357.             push bp                 ;Set up stack frame
  1358.             mov bp,sp
  1359.             pusha                   ;Save all registers
  1360.             push es
  1361.  
  1362.             mov es,[bfp]            ;ES = bit-file
  1363.             cmp [word es:2],1       ;Input file, can't output
  1364.             jne p4_done
  1365.  
  1366.             cmp [word bit],0        ;Check bit
  1367.             jz p4_skip
  1368.             mov al,[es:5]           ;Add bit to buffer
  1369.             or [es:4],al
  1370.  
  1371. p4_skip:    shr [byte es:5],1       ;Move to next bit
  1372.             jnz p4_done             ;Finished a byte?
  1373.  
  1374.             push [es:0] [es:4]      ;Put byte to file
  1375.             call fputc
  1376.             mov [word es:4],8000h   ;Buf = 0, Mask = 80h
  1377.  
  1378. p4_done:    pop es                  ;Restore registers
  1379.             popa
  1380.             pop bp                  ;Delete stack frame
  1381.             ret 4                   ;Return
  1382.  
  1383. EndP        putbit
  1384.  
  1385. ;****************** getbits() -- Get bits from bit-file
  1386. ;int getbits(int bfp, int count);
  1387.  
  1388. bfp         equ bp+6
  1389. count       equ bp+4
  1390.  
  1391. Proc        getbits
  1392.  
  1393.             push bp                 ;Set up stack frame
  1394.             mov bp,sp
  1395.             push es cx dx           ;Save registers
  1396.  
  1397.             mov es,[bfp]            ;ES = bit-file
  1398.             cmp [word es:2],0       ;Output file, can't input
  1399.             jne p5_done
  1400.  
  1401.             mov cx,[count]          ;CX = bit count
  1402.             xor dx,dx               ;Zero buffer
  1403.  
  1404. p5_loop:    cmp [byte es:5],80h     ;Buffer empty?
  1405.             jne p5_skip1
  1406.  
  1407.             push [es:0]             ;Get char
  1408.             call fgetc
  1409.             mov [es:4],al           ;Save char
  1410.  
  1411. p5_skip1:   mov al,[es:4]           ;Get bit
  1412.             and al,[es:5]
  1413.             ror [byte es:5],1       ;Move to next bit
  1414.  
  1415. p5_skip2:   add dx,dx               ;Shift over
  1416.             test al,al              ;If bit = 1,
  1417.             jz $+3                  ;then add it in
  1418.             inc dx
  1419.             loop p5_loop            ;Loop back
  1420.  
  1421.             xchg ax,dx              ;AX = result
  1422.  
  1423. p5_done:    pop dx cx es            ;Restore registers
  1424.             pop bp                  ;Delete stack frame
  1425.             ret 4                   ;Return
  1426.  
  1427. EndP        getbits
  1428.  
  1429. ;****************** putbits() -- Put bits to bit-file
  1430. ;int putbits(int bfp, int code, int count);
  1431.  
  1432. bfp         equ bp+8
  1433. code        equ bp+6
  1434. count       equ bp+4
  1435.  
  1436. Proc        putbits
  1437.  
  1438.             push bp                 ;Set up stack frame
  1439.             mov bp,sp
  1440.             pusha                   ;Save all registers
  1441.  
  1442.             mov bx,[bfp]            ;BX = bit-file
  1443.             mov cx,[count]          ;CX = bit count
  1444.             mov dx,[code]           ;DX = code
  1445.             ror dx,cl               ;Put at left
  1446.  
  1447. p6_loop:    add dx,dx               ;Shift out bit
  1448.             sbb ax,ax               ;AX = bit
  1449.             push bx ax              ;Put bit
  1450.             call putbit
  1451.             loop p6_loop            ;Loop back
  1452.  
  1453.             popa                    ;Restore registers
  1454.             pop bp                  ;Delete stack frame
  1455.             ret 6                   ;Return
  1456.  
  1457. EndP        putbits
  1458.  
  1459. ;****************** getcode() -- Get optimal code from bit-file
  1460. ;int getcode(int bfp, int max);  'max' is number of possible codes
  1461.  
  1462. bfp         equ bp+6
  1463. max         equ bp+4
  1464.  
  1465. Proc        getcode
  1466.  
  1467.             push bp                 ;Set up stack frame
  1468.             mov bp,sp
  1469.             push bx cx dx si        ;Save registers
  1470.  
  1471.             mov ax,17               ;Set up for log
  1472.             mov cx,[max]
  1473.             jcxz p7_done            ;Quit on 0
  1474.  
  1475. p7_bloop:   dec ax                  ;AX = log2(max) + 1
  1476.             add cx,cx
  1477.             jnc p7_bloop
  1478.             xchg ax,cx              ;CX = AX
  1479.  
  1480.             mov si,1                ;SI = 2^CX - max
  1481.             shl si,cl
  1482.             sub si,[max]
  1483.  
  1484.             mov bx,[bfp]            ;BX = bit-file
  1485.             dec cx                  ;CX = count (log2(max))
  1486.  
  1487.             push bx cx              ;Get bits
  1488.             call getbits
  1489.             xchg ax,dx              ;Result in DX
  1490.  
  1491.             cmp dx,si               ;DX >= SI?
  1492.             jb p7_done
  1493.  
  1494.             push bx                 ;Add in another bit
  1495.             call getbit
  1496.             add dx,dx
  1497.             add dx,ax
  1498.             sub dx,si               ;Subtract out SI
  1499.  
  1500. p7_done:    xchg ax,dx              ;AX = result
  1501.             pop si dx cx bx         ;Restore registers
  1502.             pop bp                  ;Delete stack frame
  1503.             ret 4                   ;Return
  1504.  
  1505. EndP        getcode
  1506.  
  1507. ;****************** putcode() -- Put optimal code to bit-file
  1508. ;                                'max' is number of possible codes
  1509. ;int putcode(int bfp, int code, int max);
  1510.  
  1511. bfp         equ bp+8
  1512. code        equ bp+6
  1513. max         equ bp+4
  1514.  
  1515. Proc        putcode
  1516.  
  1517.             push bp                 ;Set up stack frame
  1518.             mov bp,sp
  1519.             pusha                   ;Save all registers
  1520.  
  1521.             mov ax,17               ;AX = log2(max) + 1
  1522.             mov cx,[max]
  1523.             jcxz p8_done            ;Quit on 0
  1524. p8_bloop:   dec ax
  1525.             add cx,cx
  1526.             jnc p8_bloop
  1527.             xchg ax,cx              ;CX = AX
  1528.  
  1529.             mov si,1                ;SI = 2^CX - max
  1530.             shl si,cl
  1531.             sub si,[max]
  1532.  
  1533.             mov dx,[code]           ;DX = code
  1534.             dec cx                  ;CX = bit count
  1535.  
  1536.             cmp dx,si               ;DX >= SI?
  1537.             jb p8_skip
  1538.             inc cx                  ;One more bit
  1539.             add dx,si               ;and add in SI
  1540.  
  1541. p8_skip:    push [bfp] dx cx        ;Output bit code
  1542.             call putbits
  1543.  
  1544. p8_done:    popa                    ;Restore registers
  1545.             pop bp                  ;Delete stack frame
  1546.             ret 4                   ;Return
  1547.  
  1548. EndP        putcode
  1549.  
  1550. End
  1551.  
  1552. ~~~C_MEMORY
  1553. Ideal
  1554.  
  1555. Extrn       TopByte:Word
  1556. Public      allocmem,freemem,getmfree
  1557.  
  1558. Model Tiny
  1559. P186
  1560. CodeSeg
  1561.  
  1562. ;****************** allocmem() -- Allocate memory
  1563. ;void *allocmem(unsigned nbytes);
  1564.  
  1565. nbytes      equ bp+4
  1566.  
  1567. Proc        allocmem
  1568.  
  1569.             push bp                 ;Set up stack frame
  1570.             mov bp,sp
  1571.             pusha                   ;Save registers
  1572.             push es
  1573.  
  1574.             mov dx,[bp+4]           ;DX = num. of bytes + 3
  1575.             add dx,3
  1576.             mov bx,offset TopByte   ;BX = first MCB
  1577.  
  1578. p1_loop:    mov cl,[bx+2]           ;CX = flag byte
  1579.             test cl,1               ;Not free, loop
  1580.             jnz p1_lb
  1581.             mov ax,[bx]             ;AX = size
  1582.             cmp ax,dx               ;Big enough?
  1583.             jae p1_gotit
  1584.  
  1585. p1_lb:      test cl,2               ;Last block?
  1586.             jnz p1_nope             ;Out of memory
  1587.             add bx,[bx]             ;Next block
  1588.             jmp p1_loop             ;Loop back
  1589.  
  1590. p1_gotit:   sub ax,3                ;Check for snug fit,
  1591.             cmp ax,dx               ;that is, too little
  1592.             jbe p1_snug             ;excess to split it
  1593.  
  1594.             sub ax,dx               ;AX = excess
  1595.             add ax,3
  1596.  
  1597.             mov si,bx               ;SI = split point
  1598.             add si,dx
  1599.             mov [si],ax             ;Set size of excess block
  1600.             mov [si+2],cl           ;Set flags to original values
  1601.  
  1602.             mov [bx],dx             ;Set size of present block
  1603.             mov [byte bx+2],1       ;Set flags: allocated, not last
  1604.             jmp p1_finish
  1605.  
  1606. p1_snug:    or [byte bx+2],1        ;Set allocated flag
  1607.  
  1608. p1_finish:  add bx,3                ;BX = offset of memory block
  1609.  
  1610. p1_done:    mov [bp-2],bx           ;Change pushed AX
  1611.             pop es                  ;Restore registers
  1612.             popa
  1613.             pop bp                  ;Delete stack frame
  1614.             ret 2                   ;Return
  1615.  
  1616. p1_nope:    xor bx,bx               ;Return null pointer
  1617.             jmp p1_done
  1618.  
  1619. EndP        allocmem
  1620.  
  1621. ;****************** freemem() -- Free memory
  1622. ;void freemem(void *ptr);
  1623.  
  1624. ptr         equ bp+4
  1625.  
  1626. Proc        freemem
  1627.  
  1628.             push bp                 ;Set up stack frame
  1629.             mov bp,sp
  1630.             pusha                   ;Save registers
  1631.  
  1632.             mov dx,[ptr]            ;DX = pointer
  1633.             sub dx,3                ;Point to MCB
  1634.             mov bx,offset TopByte   ;BX = first MCB
  1635.             xor si,si               ;Zero previous ptr.
  1636.  
  1637. p2_loop:    cmp bx,dx               ;Found it?
  1638.             je p2_gotit
  1639.  
  1640.             test [byte bx+2],2      ;Last block?
  1641.             jnz p2_done
  1642.             mov si,bx               ;Save block
  1643.             add bx,[bx]             ;Next block
  1644.             jmp p2_loop             ;Loop back
  1645.  
  1646. p2_gotit:   mov di,bx               ;DI = next block
  1647.             add di,[bx]
  1648.  
  1649.             test [byte bx+2],2      ;Next block allocated
  1650.             jnz p2_cont1            ;or nonexistent, can't
  1651.             mov cl,[di+2]           ;merge with it
  1652.             test cl,1
  1653.             jnz p2_done
  1654.  
  1655.             mov ax,[di]             ;Merge blocks: sum sizes,
  1656.             add [bx],ax             ;set flags of second one
  1657.             mov [bx+2],cl
  1658.  
  1659. p2_cont1:   and [byte bx+2],0FEh    ;Reset allocated flag
  1660.  
  1661.             test si,si              ;Prev. block allocated
  1662.             jz p2_done              ;or nonexistent, can't
  1663.             mov cl,[si+2]           ;merge with it
  1664.             test cl,1
  1665.             jnz p2_done
  1666.  
  1667.             mov ax,[bx]             ;Merge blocks: sum sizes,
  1668.             add [si],ax             ;set flags of second one
  1669.             mov cl,[bx+2]
  1670.             mov [si+2],cl
  1671.  
  1672. p2_done:    popa                    ;Restore registers
  1673.             pop bp                  ;Delete stack frame
  1674.             ret 2                   ;Return
  1675.  
  1676. EndP        freemem
  1677.  
  1678. ;****************** getmfree() -- Return largest free memory block
  1679. ;unsigned getmfree(void);
  1680.  
  1681. ptr         equ bp+4
  1682.  
  1683. Proc        getmfree
  1684.  
  1685.             push bp                 ;Set up stack frame
  1686.             mov bp,sp
  1687.             push bx                 ;Save registers
  1688.  
  1689.             mov bx,offset TopByte   ;BX = first MCB
  1690.             xor ax,ax               ;Zero counter
  1691.  
  1692. p3_loop:    test [byte bx+2],1      ;Not free, skip
  1693.             jnz p3_skip
  1694.             cmp ax,[bx]             ;Biggest so far?
  1695.             jae p3_skip
  1696.             mov ax,[bx]             ;Save largest block
  1697.  
  1698. p3_skip:    test [byte bx+2],2      ;Last block?
  1699.             jnz p3_done
  1700.             add bx,[bx]             ;Next block
  1701.             jmp p3_loop             ;Loop back
  1702.  
  1703. p3_done:    sub ax,3                ;Adjust to true size
  1704.             pop bx                  ;Restore registers
  1705.             pop bp                  ;Delete stack frame
  1706.             ret                     ;Return
  1707.  
  1708. EndP        getmfree
  1709.  
  1710. End
  1711.  
  1712. ~~~C_FARMEM
  1713. Ideal
  1714.  
  1715. Public      faralloc,farfree,getfarfree
  1716.  
  1717. Model Tiny
  1718. P186
  1719. CodeSeg
  1720.  
  1721. ;****************** faralloc() -- Allocate far memory
  1722. ;int faralloc(int nparas);
  1723.  
  1724. nparas      equ bp+4
  1725.  
  1726. Proc        faralloc
  1727.  
  1728.             push bp                 ;Set up stack frame
  1729.             mov bp,sp
  1730.             push bx                 ;Save BX
  1731.  
  1732.             mov ah,48h              ;Allocate memory
  1733.             mov bx,[nparas]         ;BX = paras
  1734.             int 21h                 ;DOS call
  1735.  
  1736.             jnc $+4                 ;No error, return pointer
  1737.             xor ax,ax               ;Error, return 0
  1738.  
  1739.             pop bx                  ;Restore BX
  1740.             pop bp                  ;Delete stack frame
  1741.             ret 2                   ;Return
  1742.  
  1743. EndP        faralloc
  1744.  
  1745. ;****************** farfree() -- Free far memory
  1746. ;void farfree(int ptr);
  1747.  
  1748. ptr         equ bp+4
  1749.  
  1750. Proc        farfree
  1751.  
  1752.             push bp                 ;Set up stack frame
  1753.             mov bp,sp
  1754.             push es ax              ;Save registers
  1755.  
  1756.             mov ah,4Ah              ;Free memory
  1757.             mov es,[ptr]            ;ES = pointer
  1758.             int 21h                 ;DOS call
  1759.  
  1760.             pop ax es               ;Restore registers
  1761.             pop bp                  ;Delete stack frame
  1762.             ret 2                   ;Return
  1763.  
  1764. EndP        farfree
  1765.  
  1766. ;****************** getfarfree() -- Return largest free far memory block
  1767. ;unsigned getfarfree(void);
  1768.  
  1769. ptr         equ bp+4
  1770.  
  1771. Proc        getfarfree
  1772.  
  1773.             push bp                 ;Set up stack frame
  1774.             mov bp,sp
  1775.             push bx                 ;Save registers
  1776.  
  1777.             mov ah,48h              ;Allocate memory
  1778.             mov bx,-1               ;-1 is invalid
  1779.             int 21h                 ;DOS call (returns an error)
  1780.             xchg ax,bx              ;AX = size of largest free block
  1781.  
  1782.             pop bx                  ;Restore registers
  1783.             pop bp                  ;Delete stack frame
  1784.             ret                     ;Return
  1785.  
  1786. EndP        getfarfree
  1787.  
  1788. End
  1789.  
  1790. ~~~C_ATOI
  1791. Ideal
  1792.  
  1793. Public      atoi,atol
  1794.  
  1795. Model Tiny
  1796. CodeSeg
  1797. P186
  1798.  
  1799. ;****************** atoi() -- Convert string to int
  1800. ;int atoi(char *strp);
  1801.  
  1802. strp        equ bp+4
  1803.  
  1804. Proc        atoi
  1805.  
  1806.             push bp                 ;Set up stack frame
  1807.             mov bp,sp
  1808.  
  1809.             push dx [strp]          ;Save DX, call atol
  1810.             call atol
  1811.  
  1812.             pop dx                  ;Restore DX
  1813.             pop bp                  ;Delete stack frame
  1814.             ret 2                   ;Return
  1815.  
  1816. EndP        atoi
  1817.  
  1818. ;****************** atol() -- Convert string to long
  1819. ;long atol(char *strp);
  1820.  
  1821. strp        equ bp+4
  1822.  
  1823. Proc        atol
  1824.  
  1825.             push bp                 ;Set up stack frame
  1826.             mov bp,sp
  1827.             push bx cx si di        ;Save registers
  1828.  
  1829.             mov si,[strp]           ;SI = string
  1830.  
  1831.             xor ax,ax               ;DX:AX = 0
  1832.             xor bh,bh               ;BH = 0
  1833.             cwd
  1834.             mov cx,10               ;CX = 10
  1835.  
  1836. p1_ploop:   mov bl,[si]             ;Load char
  1837.             inc si
  1838.             cmp bl,' '              ;Loop while char is space
  1839.             je p1_ploop             ;(20h, or 09h thru 0Dh)
  1840.             cmp bl,9
  1841.             jna p1_cont
  1842.             cmp bl,13
  1843.             jbe p1_ploop
  1844.  
  1845. p1_cont:    xor bp,bp               ;BP = 0
  1846.             cmp bl,'+'              ;If char = '+', ignore
  1847.             je p1_loop
  1848.             cmp bl,'-'              ;If char <> '-', keep it
  1849.             jne p1_skip
  1850.             inc bp                  ;Set negative flag
  1851.  
  1852. p1_loop:    mov bl,[si]             ;Load char
  1853.             inc si
  1854.  
  1855. p1_skip:    cmp bl,'9'              ;Not a digit, finish
  1856.             ja p1_finish
  1857.             sub bl,'0'
  1858.             jc p1_finish
  1859.  
  1860.             mul cx                  ;Multiply by 10
  1861.             add ax,bx               ;Add in digit...
  1862.             adc dl,dh
  1863.             jz p1_loop              ;Not a long yet, loop
  1864.             jmp p1_lload            ;Go into long loop
  1865.  
  1866. p1_lloop:   mov di,dx               ;DI = old hi word
  1867.             mov cx,10               ;Multiply old lo word by 10
  1868.             mul cx
  1869.             xchg dx,cx              ;CX = new hi word(1)
  1870.             xchg ax,di              ;DI = new lo word
  1871.             mul dx                  ;Multiply old hi word by 10
  1872.             xchg ax,dx              ;DX = new hi word(2)
  1873.             xchg ax,di              ;AX = new lo word
  1874.             add ax,bx               ;Add in digit
  1875.             adc dx,cx               ;DX:AX = new value
  1876.  
  1877. p1_lload:   mov bl,[si]             ;load char
  1878.             inc si
  1879.  
  1880.             cmp bl,'9'              ;Not a digit, finish
  1881.             ja p1_finish
  1882.             sub bl,'0'
  1883.             jnc p1_lloop            ;Jump to loop
  1884.  
  1885. p1_finish:  dec bp                  ;Positive, don't negate
  1886.             jl p1_done
  1887.  
  1888.             neg dx                  ;Negate the result
  1889.             neg ax
  1890.             sbb dx,0
  1891.  
  1892. p1_done:    pop di si cx bx         ;Restore registers
  1893.             pop bp                  ;Delete stack frame
  1894.             ret 2                   ;Return
  1895.  
  1896. EndP        atol
  1897.  
  1898. End
  1899.  
  1900. ~~~C_ITOA
  1901. Ideal
  1902.  
  1903. Public      itoa
  1904.  
  1905. Model Tiny
  1906. CodeSeg
  1907. P186
  1908.  
  1909. ;****************** itoa() -- Convert int to string
  1910. ;void itoa(int n, char *strp);
  1911.  
  1912. n           equ bp+6
  1913. strp        equ bp+4
  1914.  
  1915. Proc        itoa
  1916.  
  1917.             push bp                 ;Set up stack frame
  1918.             mov bp,sp
  1919.             pusha                   ;Save all registers
  1920.  
  1921.             mov ax,[n]              ;AX = n
  1922.             mov di,[strp]           ;DI = string pointer
  1923.  
  1924.             test ax,ax              ;Negative?
  1925.             jge p1_noneg
  1926.             mov [byte di],'-'       ;Store minus sign
  1927.             inc di
  1928.             neg ax                  ;Make it positive
  1929.  
  1930. p1_noneg:   xor cx,cx               ;Zero CX
  1931.             test ax,ax              ;Check for zero
  1932.             jnz p1_nozero
  1933.  
  1934.             push '0'                ;Push a zero
  1935.             inc cx                  ;One digit
  1936.             jmp p1_ploop
  1937.  
  1938. p1_nozero:  mov si,10               ;SI = 10
  1939.  
  1940. p1_dloop:   xor dx,dx               ;Divide by 10
  1941.             div si
  1942.             mov bl,dl               ;Remainder in BL
  1943.             add bl,30h              ;Convert to digit
  1944.             push bx                 ;Push digit
  1945.             inc cx
  1946.             test ax,ax              ;Loop back
  1947.             jnz p1_dloop
  1948.  
  1949. p1_ploop:   pop ax                  ;Pop digit
  1950.             mov [di],al             ;Store digit
  1951.             inc di
  1952.             loop p1_ploop           ;Loop back
  1953.  
  1954.             mov [byte di],0         ;Add the null byte
  1955.  
  1956.             popa                    ;Restore registers
  1957.             pop bp                  ;Delete stack frame
  1958.             ret 4                   ;Return
  1959.  
  1960. EndP        itoa
  1961.  
  1962. End
  1963.  
  1964. ~~~C_LTOA
  1965. Ideal
  1966.  
  1967. Extrn       itoa:near
  1968. Public      ltoa
  1969.  
  1970. Model Tiny
  1971. CodeSeg
  1972. P186
  1973.  
  1974. ;****************** ltoa() -- Convert long to string
  1975. ;void ltoa(long n, char *strp);
  1976.  
  1977. n           equ bp+6
  1978. strp        equ bp+4
  1979.  
  1980. Proc        ltoa
  1981.  
  1982.             push bp                 ;Set up stack frame
  1983.             mov bp,sp
  1984.             pusha                   ;Save all registers
  1985.  
  1986.             mov di,[strp]           ;DI = string pointer
  1987.             mov dx,[n+2]            ;DX:AX = n
  1988.             mov ax,[n]
  1989.             test dx,dx              ;DX = 0, use itoa
  1990.             jnz p1_chkn
  1991.             cmp ax,8000h
  1992.             jnb p1_chkn
  1993.  
  1994. p1_itoa:    push ax di              ;Convert with itoa
  1995.             call itoa
  1996.             jmp p1_done             ;Return
  1997.  
  1998. p1_chkn:    cmp dx,-1               ;DX = -1 and AX <> 0, use itoa
  1999.             jne p1_strp
  2000.             cmp ax,8000h
  2001.             jae p1_itoa
  2002.  
  2003. p1_strp:    test dx,dx              ;Negative?
  2004.             jge p1_noneg
  2005.             mov [byte di],'-'       ;Store minus sign
  2006.             inc di
  2007.             neg dx                  ;Make it positive
  2008.             neg ax
  2009.             sbb dx,0
  2010.  
  2011. p1_noneg:   mov bx,50000            ;Divide by 100000
  2012.             div bx
  2013.             xor bx,bx               ;Zero BX
  2014.             shr ax,1
  2015.             adc bx,0                ;BX = rem flag
  2016.             push bx dx              ;Save BX, DX
  2017.  
  2018.             test ax,ax              ;Check for zero
  2019.             jz p1_cont
  2020.  
  2021.             xor cx,cx               ;Zero CX
  2022.             mov si,10               ;SI = 10
  2023.  
  2024. p1_dloop:   xor dx,dx               ;Divide by 10
  2025.             div si
  2026.             mov bl,dl               ;Remainder in BL
  2027.             add bl,30h              ;Convert to digit
  2028.             push bx                 ;Push digit
  2029.             inc cx
  2030.             test ax,ax              ;Loop back
  2031.             jnz p1_dloop
  2032.  
  2033. p1_ploop:   pop ax                  ;Pop digit
  2034.             mov [di],al             ;Store digit
  2035.             inc di
  2036.             loop p1_ploop           ;Loop back
  2037.  
  2038. p1_cont:    pop ax bx               ;Restore low data
  2039.             xor dx,dx               ;Zero DX
  2040.             test bx,bx              ;Check for high part
  2041.             jz p1_nohigh
  2042.  
  2043.             add ax,50000            ;Add in 50000
  2044.             adc dx,0
  2045.  
  2046. p1_nohigh:  mov si,10               ;SI = 10
  2047.             mov cx,5                ;5 digits
  2048.             jmp p1_skip1
  2049.  
  2050. p1_dloopb:  xor dx,dx               ;Zero DX
  2051. p1_skip1:   div si                  ;Divide by 10
  2052.             mov bl,dl               ;Remainder in BL
  2053.             add bl,30h              ;Convert to digit
  2054.             push bx                 ;Push digit
  2055.             loop p1_dloopb          ;Loop back
  2056.  
  2057.             mov cx,5                ;5 digits
  2058.  
  2059. p1_ploopb:  pop ax                  ;Pop digit
  2060.             mov [di],al             ;Store digit
  2061.             inc di
  2062.             loop p1_ploopb          ;Loop back
  2063.  
  2064.             mov [byte di],0         ;Add the null byte
  2065.  
  2066. p1_done:    popa                    ;Restore registers
  2067.             pop bp                  ;Delete stack frame
  2068.             ret 6                   ;Return
  2069.  
  2070. EndP        ltoa
  2071.  
  2072. End
  2073.  
  2074. ~~~C_PUTS
  2075. Ideal
  2076.  
  2077. Extrn       PUT_CHAR:near
  2078. Public      puts,xputs
  2079.  
  2080. Model Tiny
  2081. CodeSeg
  2082. P186
  2083.  
  2084. ;****************** puts() -- Print string
  2085. ;void puts(char *strp);
  2086.  
  2087. strp        equ bp+4
  2088.  
  2089. Proc        puts
  2090.  
  2091.             push bp                 ;Set up stack frame
  2092.             mov bp,sp
  2093.             pusha                   ;Save all registers
  2094.  
  2095.             mov si,[strp]           ;SI = string pointer
  2096.  
  2097. p1_loop:    lodsb                   ;Get char
  2098.             test al,al              ;Check for null
  2099.             jz p1_done
  2100.             call PUT_CHAR           ;Output char
  2101.             jmp p1_loop             ;Loop back
  2102.  
  2103. p1_done:    popa                    ;Restore registers
  2104.             pop bp                  ;Delete stack frame
  2105.             ret 2                   ;Return
  2106.  
  2107. EndP        puts
  2108.  
  2109. ;****************** xputs() -- Print string, generalized
  2110. ;void xputs(void *func, int strp);
  2111.  
  2112. func        equ bp+6
  2113. strp        equ bp+4
  2114.  
  2115. Proc        xputs
  2116.  
  2117.             push bp                 ;Set up stack frame
  2118.             mov bp,sp
  2119.             pusha                   ;Save all registers
  2120.  
  2121.             mov si,[strp]           ;SI = string pointer
  2122.             mov bx,[func]           ;BX = function
  2123.  
  2124. p2_loop:    lodsb                   ;Get char
  2125.             test al,al              ;Check for null
  2126.             jz p2_done
  2127.             push ax                 ;Output char
  2128.             call bx
  2129.             jmp p2_loop             ;Loop back
  2130.  
  2131. p2_done:    popa                    ;Restore registers
  2132.             pop bp                  ;Delete stack frame
  2133.             ret 4                   ;Return
  2134.  
  2135. EndP        xputs
  2136.  
  2137. End
  2138.  
  2139. ~~~C_FPUTS
  2140. Ideal
  2141.  
  2142. Extrn       fputc:near
  2143. Public      fputs
  2144.  
  2145. Model Tiny
  2146. CodeSeg
  2147. P186
  2148.  
  2149. ;****************** fputs() -- Print string to file
  2150. ;int fputs(int fp, char *strp);
  2151.  
  2152. fp          equ bp+6
  2153. strp        equ bp+4
  2154.  
  2155. Proc        fputs
  2156.  
  2157.             push bp                 ;Set up stack frame
  2158.             mov bp,sp
  2159.             push bx si              ;Save registers
  2160.  
  2161.             mov si,[strp]           ;SI = string pointer
  2162.             mov bx,[fp]             ;BX = file pointer
  2163.  
  2164. p1_loop:    lodsb                   ;Get char
  2165.             test al,al              ;Check for null
  2166.             jz p1_done
  2167.             push bx ax              ;Output char:
  2168.             call fputc              ;fputc(fp, AX);
  2169.             test ax,ax
  2170.             jnl p1_loop             ;Loop back
  2171.  
  2172. p1_done:    pop si bx               ;Restore registers
  2173.             pop bp                  ;Delete stack frame
  2174.             ret 4                   ;Return
  2175.  
  2176. EndP        fputs
  2177.  
  2178. End
  2179.  
  2180. ~~~C_GETS
  2181. Ideal
  2182.  
  2183. Public      gets,xgets
  2184.  
  2185. Model Tiny
  2186. CodeSeg
  2187. P186
  2188.  
  2189. ;****************** gets() -- Get string
  2190. ;void gets(char *strp, int max);
  2191.  
  2192. strp        equ bp+6
  2193. max         equ bp+4
  2194.  
  2195. Proc        gets
  2196.  
  2197.             push bp                 ;Set up stack frame
  2198.             mov bp,sp
  2199.             pusha                   ;Save all registers
  2200.             push es
  2201.  
  2202.             mov di,[strp]           ;DI = string pointer
  2203.             mov cx,[max]            ;CX = max string length
  2204.             dec cx
  2205.  
  2206. p1_loop:    xor ax,ax               ;Get key
  2207.             int 16h
  2208.             test al,al              ;Ignore extended keys
  2209.             jz p1_loop
  2210.             cmp al,8                ;Backspace?
  2211.             je p1_bksp
  2212.  
  2213.             int 29h                 ;Show char (on screen)
  2214.             cmp al,13               ;<Enter> = done
  2215.             je p1_done
  2216.             jcxz p1_loop            ;Maxed out, don't store
  2217.             mov [di],al             ;Store char
  2218.             inc di
  2219.             dec cx                  ;Decrement maximum
  2220.             jmp p1_loop             ;Loop back
  2221.  
  2222. p1_bksp:    cmp di,[strp]           ;At beginning, do nothing
  2223.             je p1_loop
  2224.             dec di                  ;Decrement string pointer
  2225.             inc cx                  ;Increment maximum
  2226.  
  2227.             push cx                 ;Save CX
  2228.             mov ah,0Fh              ;Get video page
  2229.             int 10h
  2230.             mov ah,3                ;Get cursor position
  2231.             int 10h                 ;in DH/DL
  2232.             dec dx                  ;Move left one column
  2233.             test dl,dl              ;if at zero moves up too
  2234.             jnl p1_nowrap
  2235.  
  2236.             push 0                  ;DL = last column
  2237.             pop es
  2238.             mov dl,[es:044Ah]
  2239.             dec dx
  2240.  
  2241. p1_nowrap:  mov ah,2                ;Set cursor position
  2242.             int 10h
  2243.             mov ax,0A20h            ;Clear char at current
  2244.             mov cx,1                ;cursor position
  2245.             int 10h
  2246.             pop cx                  ;Restore CX
  2247.             jmp p1_loop             ;Loop back
  2248.  
  2249. p1_done:    mov al,10               ;Output LF
  2250.             int 29h
  2251.             mov [byte di],0         ;Terminate string
  2252.             pop es                  ;Restore registers
  2253.             popa
  2254.             pop bp                  ;Delete stack frame
  2255.             ret 4                   ;Return
  2256.  
  2257. EndP        gets
  2258.  
  2259. ;****************** xgets() -- Get string, generalized
  2260. ;void xgets(void *func, char *strp, int max, int term);
  2261.  
  2262. strp        equ bp+10
  2263. func        equ bp+8
  2264. max         equ bp+6
  2265. term        equ bp+4
  2266.  
  2267. Proc        xgets
  2268.  
  2269.             push bp                 ;Set up stack frame
  2270.             mov bp,sp
  2271.             pusha                   ;Save all registers
  2272.  
  2273.             mov di,[strp]           ;DI = string pointer
  2274.             mov bx,[func]           ;BX = function
  2275.             mov cx,[max]            ;CX = max string length
  2276.             dec cx
  2277.             mov dx,[term]           ;DX = terminator
  2278.  
  2279. p2_loop:    call bx                 ;Get char
  2280.             cmp al,dl               ;Check for terminator
  2281.             je p2_done
  2282.             jcxz p1_loop            ;Maxed out, don't store
  2283.             mov [di],al             ;Store char
  2284.             inc di
  2285.             dec cx                  ;Decrement maximum
  2286.             jmp p2_loop             ;Loop back
  2287.  
  2288. p2_done:    mov [byte di],0         ;Terminate string
  2289.             popa                    ;Restore registers
  2290.             pop bp                  ;Delete stack frame
  2291.             ret 8                   ;Return
  2292.  
  2293. EndP        xgets
  2294.  
  2295. End
  2296.  
  2297. ~~~C_FGETS
  2298. Ideal
  2299.  
  2300. Extrn       fgetc:near
  2301. Public      fgets
  2302.  
  2303. Model Tiny
  2304. CodeSeg
  2305. P186
  2306.  
  2307. ;****************** fgets() -- Get string from file
  2308. ;void fgets(int fp, char *strp, int max);
  2309.  
  2310. fp          equ bp+8
  2311. strp        equ bp+6
  2312. max         equ bp+4
  2313.  
  2314. Proc        fgets
  2315.  
  2316.             push bp                 ;Set up stack frame
  2317.             mov bp,sp
  2318.             push bx cx dx di        ;Save all registers
  2319.  
  2320.             mov di,[strp]           ;DI = string pointer
  2321.             mov bx,[fp]             ;BX = file pointer
  2322.             mov cx,[max]            ;CX = max string length
  2323.             dec cx
  2324.  
  2325. p1_loop:    push bx                 ;Get char
  2326.             call fgetc
  2327.             test ax,ax              ;Check for EOF
  2328.             jl p1_quit
  2329.             cmp al,13               ;CR = done
  2330.             je p1_done
  2331.             jcxz p1_loop            ;Maxed out, don't store
  2332.             mov [di],al             ;Store char
  2333.             inc di
  2334.             dec cx                  ;Decrement maximum
  2335.             jmp p1_loop             ;Loop back
  2336.  
  2337. p1_done:    push bx                 ;Remove LF
  2338.             call fgetc
  2339.             xor ax,ax
  2340. p1_quit:    mov [byte di],0         ;Terminate string
  2341.             pop di dx cx bx         ;Restore registers
  2342.             pop bp                  ;Delete stack frame
  2343.             ret 6                   ;Return
  2344.  
  2345. EndP        fgets
  2346.  
  2347. End
  2348.  
  2349. ~~~C_PRTBUF
  2350. Ideal
  2351.  
  2352. Public      PRT_BUF
  2353.  
  2354. Model Tiny
  2355. CodeSeg
  2356. P186
  2357.  
  2358. ;****************** PRT_BUF -- String buffer for printf(), etc.
  2359.  
  2360. PRT_BUF     db 20 dup(0)
  2361.  
  2362. End
  2363.  
  2364. ~~~C_PRINTF
  2365. Ideal
  2366.  
  2367. Extrn       PRT_BUF:byte,itoa:near,ltoa:near
  2368. Extrn       PUT_CHAR:near
  2369. Public      printf
  2370.  
  2371. Model Tiny
  2372. CodeSeg
  2373. P186
  2374.  
  2375. ;****************** printf() -- Print formatted string
  2376. ;void printf(char *fmt, void *args);
  2377.  
  2378. fmt         equ bp+6
  2379. args        equ bp+4
  2380.  
  2381. Proc        printf
  2382.  
  2383.             push bp                 ;Set up stack frame
  2384.             mov bp,sp
  2385.             pusha                   ;Save all registers
  2386.  
  2387.             mov si,[fmt]            ;SI = string pointer
  2388.             mov bx,[args]           ;BX = arg pointer
  2389.  
  2390. p1_loop:    lodsb                   ;Get char
  2391.             test al,al              ;Check for null
  2392.             jz p1_done
  2393.             cmp al,'%'              ;Check for '%'
  2394.             je p1_proc
  2395. p1_putc:    call PUT_CHAR           ;Output char
  2396.             jmp p1_loop             ;Loop back
  2397.  
  2398. p1_proc:    lodsb                   ;Get char
  2399.             test al,al              ;Check for null
  2400.             jz p1_done
  2401.             cmp al,'%'              ; %% = percent
  2402.             je p1_putc
  2403.             cmp al,'d'              ; %d = integer
  2404.             je p1_int
  2405.             cmp al,'l'              ; %l = long int
  2406.             je p1_long
  2407.             cmp al,'x'              ; %x = hex
  2408.             je p1_hex
  2409.             cmp al,'c'              ; %c = char
  2410.             je p1_char
  2411.             cmp al,'s'              ; %s = string
  2412.             je p1_str
  2413.             jmp p1_loop             ;Invalid, ignore
  2414.  
  2415. p1_done:    popa                    ;Restore registers
  2416.             pop bp                  ;Delete stack frame
  2417.             ret 4                   ;Return
  2418.  
  2419. p1_long:    lodsb                   ;Get char
  2420.             test al,al              ;Check for null
  2421.             jz p1_done
  2422.             cmp al,'d'              ; %ld = long integer
  2423.             je p1_lint
  2424.             cmp al,'x'              ; %lx = long hex
  2425.             je p1_lhex
  2426.             jmp p1_loop             ;Invalid, ignore
  2427.  
  2428. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2429.             push offset PRT_BUF
  2430.             call itoa
  2431.             inc bx                  ;Advance pointer
  2432.             inc bx
  2433.             mov di,offset PRT_BUF   ;Print alpha string
  2434.             jmp p1_alpha
  2435.  
  2436. p1_lint:    push [word bx+2]
  2437.             push [word bx]          ;ltoa(*bx, PRT_BUF);
  2438.             push offset PRT_BUF
  2439.             call ltoa
  2440.             add bx,4                ;Advance pointer
  2441.             mov di,offset PRT_BUF   ;Print alpha string
  2442.             jmp p1_alpha
  2443.  
  2444. p1_hex:     mov ax,[bx]             ;AX = arg
  2445.             call p1_chex            ;Convert to hex
  2446.             inc bx                  ;Advance pointer
  2447.             inc bx
  2448.             jmp p1_loop             ;Loop back
  2449.  
  2450. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2451.             call p1_chex            ;Convert to hex
  2452.             mov ax,[bx]             ;AX = low word
  2453.             call p1_chex            ;Convert to hex
  2454.             add bx,4                ;Advance pointer
  2455.             jmp p1_loop             ;Loop back
  2456.  
  2457. p1_char:    mov al,[bx]             ;Output char
  2458.             int 29h
  2459.             inc bx                  ;Advance pointer
  2460.             jmp p1_loop             ;Loop back
  2461.  
  2462. p1_str:     mov al,[bx]             ;Get char
  2463.             inc bx                  ;Advance pointer
  2464.             test al,al              ;Check for null
  2465.             jz p1_sdone
  2466.             call PUT_CHAR           ;Output char
  2467.             jmp p1_str              ;Loop back
  2468.  
  2469. p1_sdone:   jmp p1_loop             ;Return to main loop
  2470.  
  2471. p1_alpha:   mov al,[di]             ;Get char
  2472.             test al,al              ;Check for null
  2473.             jz p1_sdone
  2474.             call PUT_CHAR           ;Output char
  2475.             inc di                  ;Advance pointer
  2476.             jmp p1_alpha            ;Loop back
  2477.  
  2478. p1_chex:    mov cx,4                ;4 hex digits
  2479.             xchg al,ah              ;Reverse the order
  2480.             ror ah,cl               ;of the hex digits
  2481.             ror al,cl               ;in AX
  2482.  
  2483. p1_hloop:   push ax                 ;Save AX
  2484.             and al,0Fh              ;Keep 4 bits
  2485.             cmp al,0Ah              ;Compute the hex digit,
  2486.             sbb al,69h              ;using Improved Allison's Algorithm
  2487.             das
  2488.             call PUT_CHAR           ;Output char
  2489.             pop ax                  ;Restore AX
  2490.             shr ax,4                ;Shift it over
  2491.             loop p1_hloop           ;Loop back
  2492.             ret                     ;Return
  2493.  
  2494. EndP        printf
  2495.  
  2496. End
  2497.  
  2498. ~~~C_SPRINT
  2499. Ideal
  2500.  
  2501. Extrn       PRT_BUF:byte,itoa:near,ltoa:near
  2502. Public      sprintf
  2503.  
  2504. Model Tiny
  2505. CodeSeg
  2506. P186
  2507.  
  2508. ;****************** sprintf() -- Print formatted string into string
  2509. ;void sprintf(char *strp, char *fmt, void *args);
  2510.  
  2511. strp        equ bp+8
  2512. fmt         equ bp+6
  2513. args        equ bp+4
  2514.  
  2515. Proc        sprintf
  2516.  
  2517.             push bp                 ;Set up stack frame
  2518.             mov bp,sp
  2519.             pusha                   ;Save all registers
  2520.  
  2521.             mov di,[strp]           ;DI = string pointer
  2522.             mov si,[fmt]            ;SI = format pointer
  2523.             mov bx,[args]           ;BX = arg pointer
  2524.  
  2525. p1_loop:    lodsb                   ;Get char
  2526.             test al,al              ;Check for null
  2527.             jz p1_done
  2528.             cmp al,'%'              ;Check for '%'
  2529.             je p1_proc
  2530. p1_putc:    stosb                   ;Output char
  2531.             jmp p1_loop             ;Loop back
  2532.  
  2533. p1_proc:    lodsb                   ;Get char
  2534.             test al,al              ;Check for null
  2535.             jz p1_done
  2536.             cmp al,'%'              ; %% = percent
  2537.             je p1_putc
  2538.             cmp al,'d'              ; %d = integer
  2539.             je p1_int
  2540.             cmp al,'l'              ; %l = long int
  2541.             je p1_long
  2542.             cmp al,'x'              ; %x = hex
  2543.             je p1_hex
  2544.             cmp al,'c'              ; %c = char
  2545.             je p1_char
  2546.             cmp al,'s'              ; %s = string
  2547.             je p1_str
  2548.             jmp p1_loop             ;Invalid, ignore
  2549.  
  2550. p1_done:    xor al,al               ;Store a null byte
  2551.             stosb
  2552.             popa                    ;Restore registers
  2553.             pop bp                  ;Delete stack frame
  2554.             ret 6                   ;Return
  2555.  
  2556. p1_long:    lodsb                   ;Get char
  2557.             test al,al              ;Check for null
  2558.             jz p1_done
  2559.             cmp al,'d'              ; %ld = long integer
  2560.             je p1_lint
  2561.             cmp al,'x'              ; %lx = long hex
  2562.             je p1_lhex
  2563.             jmp p1_loop             ;Invalid, ignore
  2564.  
  2565. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2566.             push offset PRT_BUF
  2567.             call itoa
  2568.             inc bx                  ;Advance pointer
  2569.             inc bx
  2570.             mov bp,offset PRT_BUF   ;Print alpha string
  2571.             jmp p1_alpha
  2572.  
  2573. p1_lint:    push [word bx+2]
  2574.             push [word bx]          ;ltoa(*bx, PRT_BUF);
  2575.             push offset PRT_BUF
  2576.             call ltoa
  2577.             add bx,4                ;Advance pointer
  2578.             mov bp,offset PRT_BUF   ;Print alpha string
  2579.             jmp p1_alpha
  2580.  
  2581. p1_hex:     mov ax,[bx]             ;AX = arg
  2582.             call p1_chex            ;Convert to hex
  2583.             inc bx                  ;Advance pointer
  2584.             inc bx
  2585.             jmp p1_loop             ;Loop back
  2586.  
  2587. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2588.             call p1_chex            ;Convert to hex
  2589.             mov ax,[bx]             ;AX = low word
  2590.             call p1_chex            ;Convert to hex
  2591.             add bx,4                ;Advance pointer
  2592.             jmp p1_loop             ;Loop back
  2593.  
  2594. p1_char:    mov al,[bx]             ;Output char
  2595.             stosb
  2596.             inc bx                  ;Advance pointer
  2597.             jmp p1_loop             ;Loop back
  2598.  
  2599. p1_str:     mov al,[bx]             ;Get char
  2600.             inc bx                  ;Advance pointer
  2601.             test al,al              ;Check for null
  2602.             jz p1_sdone
  2603.             stosb                   ;Output char
  2604.             jmp p1_str              ;Loop back
  2605.  
  2606. p1_sdone:   jmp p1_loop             ;Return to main loop
  2607.  
  2608. p1_alpha:   mov al,[bp]             ;Get char
  2609.             test al,al              ;Check for null
  2610.             jz p1_sdone
  2611.             stosb                   ;Output char
  2612.             inc bp                  ;Advance pointer
  2613.             jmp p1_alpha            ;Loop back
  2614.  
  2615. p1_chex:    mov cx,4                ;4 hex digits
  2616.             xchg al,ah              ;Reverse the order
  2617.             ror ah,cl               ;of the hex digits
  2618.             ror al,cl               ;in AX
  2619.  
  2620. p1_hloop:   push ax                 ;Save AX
  2621.             and al,0Fh              ;Keep 4 bits
  2622.             cmp al,0Ah              ;Compute the hex digit,
  2623.             sbb al,69h              ;using Improved Allison's Algorithm
  2624.             das
  2625.             stosb                   ;Output char
  2626.             pop ax                  ;Restore AX
  2627.             shr ax,4                ;Shift it over
  2628.             loop p1_hloop           ;Loop back
  2629.             ret                     ;Return
  2630.  
  2631. EndP        sprintf
  2632.  
  2633. End
  2634.  
  2635. ~~~C_FPRINT
  2636. Ideal
  2637.  
  2638. Extrn       PRT_BUF:byte,fputc:near,itoa:near,ltoa:near
  2639. Public      fprintf
  2640.  
  2641. Model Tiny
  2642. CodeSeg
  2643. P186
  2644.  
  2645. ;****************** fprintf() -- Print formatted string to file
  2646. ;void fprintf(int fp, char *fmt, void *args);
  2647.  
  2648. fp          equ bp+8
  2649. fmt         equ bp+6
  2650. args        equ bp+4
  2651.  
  2652. Proc        fprintf
  2653.  
  2654.             push bp                 ;Set up stack frame
  2655.             mov bp,sp
  2656.             pusha                   ;Save all registers
  2657.  
  2658.             mov dx,[fp]             ;DX = file pointer
  2659.             mov si,[fmt]            ;SI = string pointer
  2660.             mov bx,[args]           ;BX = arg pointer
  2661.  
  2662. p1_loop:    lodsb                   ;Get char
  2663.             test al,al              ;Check for null
  2664.             jz p1_done
  2665.             cmp al,'%'              ;Check for '%'
  2666.             je p1_proc
  2667. p1_putc:    push dx ax              ;Output char
  2668.             call fputc
  2669.             jmp p1_loop             ;Loop back
  2670.  
  2671. p1_proc:    lodsb                   ;Get char
  2672.             test al,al              ;Check for null
  2673.             jz p1_done
  2674.             cmp al,'%'              ; %% = percent
  2675.             je p1_putc
  2676.             cmp al,'d'              ; %d = integer
  2677.             je p1_int
  2678.             cmp al,'l'              ; %l = long int
  2679.             je p1_long
  2680.             cmp al,'x'              ; %x = hex
  2681.             je p1_hex
  2682.             cmp al,'c'              ; %c = char
  2683.             je p1_char
  2684.             cmp al,'s'              ; %s = string
  2685.             je p1_str
  2686.             jmp p1_loop             ;Invalid, ignore
  2687.  
  2688. p1_done:    popa                    ;Restore registers
  2689.             pop bp                  ;Delete stack frame
  2690.             ret 6                   ;Return
  2691.  
  2692. p1_long:    lodsb                   ;Get char
  2693.             test al,al              ;Check for null
  2694.             jz p1_done
  2695.             cmp al,'d'              ; %ld = long integer
  2696.             je p1_lint
  2697.             cmp al,'x'              ; %lx = long hex
  2698.             je p1_lhex
  2699.             jmp p1_loop             ;Invalid, ignore
  2700.  
  2701. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2702.             push offset PRT_BUF
  2703.             call itoa
  2704.             inc bx                  ;Advance pointer
  2705.             inc bx
  2706.             mov di,offset PRT_BUF   ;Print alpha string
  2707.             jmp p1_alpha
  2708.  
  2709. p1_lint:    push [word bx+2]
  2710.             push [word bx]          ;ltoa(*bx, PRT_BUF);
  2711.             push offset PRT_BUF
  2712.             call ltoa
  2713.             add bx,4                ;Advance pointer
  2714.             mov di,offset PRT_BUF   ;Print alpha string
  2715.             jmp p1_alpha
  2716.  
  2717. p1_hex:     mov ax,[bx]             ;AX = arg
  2718.             call p1_chex            ;Convert to hex
  2719.             inc bx                  ;Advance pointer
  2720.             inc bx
  2721.             jmp p1_loop             ;Loop back
  2722.  
  2723. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2724.             call p1_chex            ;Convert to hex
  2725.             mov ax,[bx]             ;AX = low word
  2726.             call p1_chex            ;Convert to hex
  2727.             add bx,4                ;Advance pointer
  2728.             jmp p1_loop             ;Loop back
  2729.  
  2730. p1_char:    mov al,[bx]             ;Output char
  2731.             push dx ax
  2732.             call fputc
  2733.             inc bx                  ;Advance pointer
  2734.             jmp p1_loop             ;Loop back
  2735.  
  2736. p1_str:     mov al,[bx]             ;Get char
  2737.             inc bx                  ;Advance pointer
  2738.             test al,al              ;Check for null
  2739.             jz p1_sdone
  2740.             push dx ax              ;Output char
  2741.             call fputc
  2742.             jmp p1_str              ;Loop back
  2743.  
  2744. p1_sdone:   jmp p1_loop             ;Return to main loop
  2745.  
  2746. p1_alpha:   mov al,[di]             ;Get char
  2747.             test al,al              ;Check for null
  2748.             jz p1_sdone
  2749.             push dx ax              ;Output char
  2750.             call fputc
  2751.             inc di                  ;Advance pointer
  2752.             jmp p1_alpha            ;Loop back
  2753.  
  2754. p1_chex:    mov cx,4                ;4 hex digits
  2755.             xchg al,ah              ;Reverse the order
  2756.             ror ah,cl               ;of the hex digits
  2757.             ror al,cl               ;in AX
  2758.  
  2759. p1_hloop:   push ax                 ;Save AX
  2760.             and al,0Fh              ;Keep 4 bits
  2761.             cmp al,0Ah              ;Compute the hex digit,
  2762.             sbb al,69h              ;using Improved Allison's Algorithm
  2763.             das
  2764.             push dx ax              ;Output char
  2765.             call fputc
  2766.             pop ax                  ;Restore AX
  2767.             shr ax,4                ;Shift it over
  2768.             loop p1_hloop           ;Loop back
  2769.             ret                     ;Return
  2770.  
  2771. EndP        fprintf
  2772.  
  2773. End
  2774.  
  2775. ~~~C_XPRINT
  2776. Ideal
  2777.  
  2778. Extrn       PRT_BUF:byte,itoa:near,ltoa:near
  2779. Public      xprintf
  2780.  
  2781. Model Tiny
  2782. CodeSeg
  2783. P186
  2784.  
  2785. ;****************** xprintf() -- Print formatted string, generalized
  2786. ;void xprintf(void *func, char *fmt, void *args);
  2787.  
  2788. func        equ bp+8
  2789. fmt         equ bp+6
  2790. args        equ bp+4
  2791.  
  2792. Proc        xprintf
  2793.  
  2794.             push bp                 ;Set up stack frame
  2795.             mov bp,sp
  2796.             pusha                   ;Save all registers
  2797.  
  2798.             mov dx,[func]           ;DX = function pointer
  2799.             mov si,[fmt]            ;SI = string pointer
  2800.             mov bx,[args]           ;BX = arg pointer
  2801.  
  2802. p1_loop:    lodsb                   ;Get char
  2803.             test al,al              ;Check for null
  2804.             jz p1_done
  2805.             cmp al,'%'              ;Check for '%'
  2806.             je p1_proc
  2807. p1_putc:    push ax                 ;Output char
  2808.             call dx
  2809.             jmp p1_loop             ;Loop back
  2810.  
  2811. p1_proc:    lodsb                   ;Get char
  2812.             test al,al              ;Check for null
  2813.             jz p1_done
  2814.             cmp al,'%'              ; %% = percent
  2815.             je p1_putc
  2816.             cmp al,'d'              ; %d = integer
  2817.             je p1_int
  2818.             cmp al,'l'              ; %l = long int
  2819.             je p1_long
  2820.             cmp al,'x'              ; %x = hex
  2821.             je p1_hex
  2822.             cmp al,'c'              ; %c = char
  2823.             je p1_char
  2824.             cmp al,'s'              ; %s = string
  2825.             je p1_str
  2826.             jmp p1_loop             ;Invalid, ignore
  2827.  
  2828. p1_done:    popa                    ;Restore registers
  2829.             pop bp                  ;Delete stack frame
  2830.             ret 6                   ;Return
  2831.  
  2832. p1_long:    lodsb                   ;Get char
  2833.             test al,al              ;Check for null
  2834.             jz p1_done
  2835.             cmp al,'d'              ; %ld = long integer
  2836.             je p1_lint
  2837.             cmp al,'x'              ; %lx = long hex
  2838.             je p1_lhex
  2839.             jmp p1_loop             ;Invalid, ignore
  2840.  
  2841. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2842.             push offset PRT_BUF
  2843.             call itoa
  2844.             inc bx                  ;Advance pointer
  2845.             inc bx
  2846.             mov di,offset PRT_BUF   ;Print alpha string
  2847.             jmp p1_alpha
  2848.  
  2849. p1_lint:    push [word bx+2]
  2850.             push [word bx]          ;ltoa(*bx, PRT_BUF);
  2851.             push offset PRT_BUF
  2852.             call ltoa
  2853.             add bx,4                ;Advance pointer
  2854.             mov di,offset PRT_BUF   ;Print alpha string
  2855.             jmp p1_alpha
  2856.  
  2857. p1_hex:     mov ax,[bx]             ;AX = arg
  2858.             call p1_chex            ;Convert to hex
  2859.             inc bx                  ;Advance pointer
  2860.             inc bx
  2861.             jmp p1_loop             ;Loop back
  2862.  
  2863. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2864.             call p1_chex            ;Convert to hex
  2865.             mov ax,[bx]             ;AX = low word
  2866.             call p1_chex            ;Convert to hex
  2867.             add bx,4                ;Advance pointer
  2868.             jmp p1_loop             ;Loop back
  2869.  
  2870. p1_char:    mov al,[bx]             ;Output char
  2871.             push ax
  2872.             call dx
  2873.             inc bx                  ;Advance pointer
  2874.             jmp p1_loop             ;Loop back
  2875.  
  2876. p1_str:     mov al,[bx]             ;Get char
  2877.             inc bx                  ;Advance pointer
  2878.             test al,al              ;Check for null
  2879.             jz p1_sdone
  2880.             push ax                 ;Output char
  2881.             call dx
  2882.             jmp p1_str              ;Loop back
  2883.  
  2884. p1_sdone:   jmp p1_loop             ;Return to main loop
  2885.  
  2886. p1_alpha:   mov al,[di]             ;Get char
  2887.             test al,al              ;Check for null
  2888.             jz p1_sdone
  2889.             push ax                 ;Output char
  2890.             call dx
  2891.             inc di                  ;Advance pointer
  2892.             jmp p1_alpha            ;Loop back
  2893.  
  2894. p1_chex:    mov cx,4                ;4 hex digits
  2895.             xchg al,ah              ;Reverse the order
  2896.             ror ah,cl               ;of the hex digits
  2897.             ror al,cl               ;in AX
  2898.  
  2899. p1_hloop:   push ax                 ;Save AX
  2900.             and al,0Fh              ;Keep 4 bits
  2901.             cmp al,0Ah              ;Compute the hex digit,
  2902.             sbb al,69h              ;using Improved Allison's Algorithm
  2903.             das
  2904.             push ax                 ;Output char
  2905.             call dx
  2906.             pop ax                  ;Restore AX
  2907.             shr ax,4                ;Shift it over
  2908.             loop p1_hloop           ;Loop back
  2909.             ret                     ;Return
  2910.  
  2911. EndP        xprintf
  2912.  
  2913. End
  2914.  
  2915. ~~~C_CPULVL
  2916. Ideal
  2917.  
  2918. Public      cputype
  2919.  
  2920. Model Tiny
  2921. P186
  2922. CodeSeg
  2923.  
  2924. ;**************************** cputype() -- Returns CPU level
  2925. ;int cputype(void);
  2926.  
  2927. Proc        cputype
  2928.  
  2929.             pusha              ;Save all registers
  2930.  
  2931.             call p1_getcpu     ;Call main procedure
  2932.  
  2933.             shr ax,8           ;AL = AH, AH = 0
  2934.             mov bp,sp          ;Change pushed AX
  2935.             mov [bp+14],ax
  2936.             popa               ;Restore registers
  2937.             ret                ;Return
  2938.  
  2939. p1_getcpu:  mov cx,0121h       ;If CH can be shifted by 21h,
  2940.             shl ch,cl          ;then it's an 8086, because
  2941.             jz p1_8086         ;a 186+ limits shift counts.
  2942.  
  2943.             push sp            ;If SP is pushed as its
  2944.             pop ax             ;original value, then
  2945.             cmp ax,sp          ;it's a 286+.
  2946.             jne p1_186
  2947.  
  2948.             pushf              ;Save flags
  2949.             cli                ;No interrupts
  2950.             pushf              ;AX = flags
  2951.             pop ax
  2952.             xor ax,7000h       ;Toggle IOPL bit
  2953.             push ax            ;Flags = AX
  2954.             popf
  2955.             pushf              ;BX = flags
  2956.             pop bx
  2957.             popf               ;Restore flags
  2958.             cmp ax,bx          ;If the bit was not
  2959.             jne p1_286         ;reset, it's a 386+
  2960. P386
  2961.             push bp            ;Align stack to dword
  2962.             mov bp,sp
  2963.             and sp,0FFFCh
  2964.             pushfd             ;Save eflags
  2965.             cli                ;No interrupts
  2966.             pushfd             ;EAX = eflags
  2967.             pop eax
  2968.             mov ebx,eax        ;EBX = eflags
  2969.             xor eax,40000h     ;Toggle AC bit
  2970.             push eax           ;Eflags = EAX
  2971.             popfd
  2972.             pushfd             ;EAX = eflags
  2973.             pop eax
  2974.             popfd              ;Restore eflags
  2975.             mov sp,bp          ;Restore stack
  2976.             pop bp
  2977.             cmp eax,ebx        ;If the bit was not
  2978.             je p1_386          ;reset, it's a 486+
  2979.  
  2980.             pushfd             ;Save eflags
  2981.             cli                ;No interrupts
  2982.             pushfd             ;EAX = eflags
  2983.             pop eax
  2984.             xor eax,200000h    ;Toggle ID bit
  2985.             push eax           ;Eflags = EAX
  2986.             popfd
  2987.             pushfd             ;EBX = eflags
  2988.             pop ebx
  2989.             popfd              ;Restore eflags
  2990.             cmp eax,ebx        ;If the bit was not
  2991.             jne p1_486         ;reset, it's a 586+
  2992. P586
  2993.             xor eax,eax        ;EAX = 1
  2994.             inc ax
  2995.             cpuid              ;Get CPU type
  2996.             ret                ;Return
  2997. P186
  2998. p1_486:     mov ah,4           ;486, return 4
  2999.             ret
  3000.  
  3001. p1_386:     mov ah,3           ;386, return 3
  3002.             ret
  3003.  
  3004. p1_286:     mov ah,2           ;286, return 2
  3005.             ret
  3006.  
  3007. p1_186:     mov ah,1           ;186, return 1
  3008.             ret
  3009.  
  3010. p1_8086:    mov ah,0           ;8086, return 0
  3011.             ret
  3012.  
  3013. EndP        cputype
  3014.  
  3015. End
  3016.  
  3017. ~~~C_FPULVL
  3018. Ideal
  3019.  
  3020. Public      fputype
  3021.  
  3022. Model Tiny
  3023. P186
  3024. CodeSeg
  3025.  
  3026. ;**************************** fputype() -- Returns FPU level, init FPU
  3027. ;int fputype(void);                        -1 means no FPU
  3028.  
  3029. Proc        fputype
  3030.  
  3031.             pusha              ;Save all registers
  3032.  
  3033.             call p2_getfpu     ;Get FPU type
  3034.  
  3035.             mov bp,sp          ;Change pushed AX
  3036.             mov [bp+14],ax
  3037.             popa               ;Restore registers
  3038.             ret                ;Return
  3039. P8087
  3040. p2_getfpu:  fninit             ;Initialize FPU
  3041.             mov [Junk],55AAh   ;Set junk value
  3042.             fnstsw [Junk]      ;Store status word
  3043.             cmp [byte Junk],0  ;If it's not 0, no FPU
  3044.             jne p2_nofpu
  3045.             fnstcw [Junk]      ;Store control word
  3046.             mov ax,[Junk]      ;If the bits are not the way
  3047.             and ax,103Fh       ;they should be, no FPU
  3048.             cmp ax,3Fh
  3049.             jne p2_nofpu
  3050.  
  3051.             and [Junk],0FF7Fh  ;Clear interrupt bit
  3052.             fldcw [Junk]       ;Load control word
  3053.             fdisi              ;Disable interrupts
  3054.             fstcw [Junk]       ;Store control word
  3055.             test [Junk],80h    ;If it changed, it's an 8087
  3056.             jnz p2_8087
  3057. P286
  3058. P287
  3059.             finit              ;Re-initialize
  3060.             fld1               ;Divide 1 by 0 to get
  3061.             fldz               ;a positive infinity
  3062.             fdiv
  3063.             fld st             ;Get a negative infinity
  3064.             fchs
  3065.             fcompp             ;Compare them
  3066.             fstsw ax           ;Store status word
  3067.             sahf               ;If the FPU thought that they
  3068.             je p2_287          ;were equal, it's a 287
  3069.  
  3070.             mov ax,3           ;387, return 3
  3071.             finit              ;Init processor
  3072.             ret
  3073.  
  3074. p2_287:     mov ax,2           ;287, return 2
  3075.             finit              ;Init processor
  3076.             ret
  3077. P186
  3078. P8087
  3079. p2_8087:    xor ax,ax          ;8087, return 0
  3080.             finit              ;Init processor
  3081.             ret
  3082.  
  3083. p2_nofpu:   mov ax,-1          ;No FPU, return -1
  3084.             ret
  3085.  
  3086. Junk        dw 0
  3087.  
  3088. EndP        fputype
  3089.  
  3090. End
  3091.  
  3092. ~~~C_RAND
  3093. Ideal
  3094.  
  3095. Public      rand,srand,truerand
  3096.  
  3097. Model Tiny
  3098. P186
  3099. CodeSeg
  3100.  
  3101. RandNum     dw 0,0                  ;Random number
  3102.  
  3103. ;****************** rand() -- Returns a random number below N
  3104. ;int rand(int max);
  3105.  
  3106. max         equ bp+4
  3107.  
  3108. Proc        rand
  3109.  
  3110.             push bp                 ;Set up stack frame
  3111.             mov bp,sp
  3112.             push bx cx dx           ;Save registers
  3113.  
  3114.             mov ax,[RandNum]        ;CX:BX = RandNum * 0019660Dh + 10DCDh
  3115.             mov dx,660Dh            ;low * low
  3116.             mul dx
  3117.             mov cx,dx               ;put it in CX:BX
  3118.             mov bx,ax
  3119.             imul ax,[RandNum],0019h ;low * high, high * low
  3120.             imul dx,[RandNum+2],660Dh
  3121.             add cx,ax               ;add them in
  3122.             add cx,dx
  3123.             add bx,0DCDh            ;add in the 10DCDh
  3124.             adc cx,0001h
  3125.  
  3126.             mov [RandNum],bx        ;Save random number
  3127.             mov [RandNum+2],cx
  3128.  
  3129.             xchg ax,cx              ;AX = low 15 bits of CX
  3130.             shl ax,1                ; plus high bit of BX
  3131.             rol bx,1
  3132.             and bx,1
  3133.             or ax,bx
  3134.             mov bx,[max]            ;BX = maximum
  3135.             xor dx,dx               ;Zero DX
  3136.             test bx,bx              ;Can't divide by zero
  3137.             jz p1_skip
  3138.             div bx                  ;Divide by BX
  3139. p1_skip:    xchg ax,dx              ;Result in AX
  3140.  
  3141.             pop dx cx bx            ;Restore registers
  3142.             pop bp                  ;Delete stack frame
  3143.             ret 2                   ;Return
  3144.  
  3145. EndP        rand
  3146.  
  3147. ;****************** srand() -- Seeds the RNG with the time
  3148. ;void srand(void);
  3149.  
  3150. Proc        srand
  3151.  
  3152.             push bp                 ;Set up stack frame
  3153.             mov bp,sp
  3154.             push ax es              ;Save registers
  3155.  
  3156.             push 40h                ;ES = BIOS segment
  3157.             pop es
  3158.  
  3159.             mov ax,[es:6Ch]         ;Get low word
  3160.             mov [RandNum],ax        ;Save it
  3161.             mov ax,[es:6Eh]         ;Get high word
  3162.             mov [RandNum+2],ax      ;Save it
  3163.  
  3164.             pop es ax               ;Restore registers
  3165.             pop bp                  ;Delete stack frame
  3166.             ret                     ;Return
  3167.  
  3168. EndP        srand
  3169.  
  3170. ;****************** truerand() -- Returns a true random number below N
  3171. ;int truerand(int max);           Extremely slow, but it works
  3172.  
  3173. max         equ bp+4
  3174.  
  3175. Proc        truerand
  3176.  
  3177.             push bp                 ;Set up stack frame
  3178.             mov bp,sp
  3179.             push bx cx dx           ;Save registers
  3180.  
  3181.             mov cx,96               ;96 iterations
  3182.             cli                     ;No interrupts allowed
  3183.  
  3184. p1_loop:    mov al,06h              ;Set timer command
  3185.             out 43h,al
  3186.             jmp $+2
  3187.             in al,40h               ;Read LSB of timer
  3188.             xor dl,al               ;XOR into DX
  3189.             jmp $+2
  3190.             in al,40h               ;Read MSB of timer
  3191.             xor dl,al               ;XOR into DX
  3192.             rol dx,3                ;Rotate left
  3193.             loop p1_loop            ;Loop back
  3194.  
  3195.             sti                     ;Enable interrupts
  3196.             xchg ax,dx              ;Result in AX
  3197.  
  3198.             mov bx,[max]            ;BX = maximum
  3199.             xor dx,dx               ;Zero DX
  3200.             test bx,bx              ;Can't divide by zero
  3201.             jz p3_skip
  3202.             div bx                  ;Divide by BX
  3203. p3_skip:    xchg ax,dx              ;Result in AX
  3204.  
  3205.             pop dx cx bx            ;Restore registers
  3206.             pop bp                  ;Delete stack frame
  3207.             ret 2                   ;Return
  3208.  
  3209. EndP        truerand
  3210.  
  3211. End
  3212.  
  3213. ~~~C_DELAY
  3214. Ideal
  3215.  
  3216. Public      delay
  3217.  
  3218. Model Tiny
  3219. P186
  3220. CodeSeg
  3221.  
  3222. ;****************** delay() -- Delay in milliseconds
  3223. ;void delay(int dtime);
  3224.  
  3225. dtime       equ bp+4
  3226.  
  3227. Proc        delay
  3228.  
  3229.             push bp                 ;Set up stack frame
  3230.             mov bp,sp
  3231.             pusha                   ;Save registers
  3232.  
  3233.             mov ax,[dtime]          ;AX = time in milliseconds
  3234.             mov dx,1000             ;Multiply by 1000
  3235.             mul dx                  ;DX:AX = time in microseconds
  3236.  
  3237.             xchg ax,dx              ;CX:DX = time
  3238.             xchg ax,cx
  3239.             mov ah,86h              ;BIOS Delay Service
  3240.             int 15h
  3241.  
  3242.             popa                    ;Restore registers
  3243.             pop bp                  ;Delete stack frame
  3244.             ret 2                   ;Return
  3245.  
  3246. EndP        delay
  3247.  
  3248. End
  3249.  
  3250. ~~~C_SOUND
  3251. Ideal
  3252.  
  3253. Public      sound,nosound
  3254.  
  3255. Model Tiny
  3256. P186
  3257. CodeSeg
  3258.  
  3259. ;****************** sound() -- Turn on speaker at specific frequency
  3260. ;void sound(int freq);
  3261.  
  3262. freq        equ bp+4
  3263.  
  3264. Proc        sound
  3265.  
  3266.             push bp                 ;Set up stack frame
  3267.             mov bp,sp
  3268.             pusha                   ;Save registers
  3269.  
  3270.             mov dx,12h              ;BX = 1193180 / freq.
  3271.             mov ax,34DCh
  3272.             mov bx,[freq]
  3273.             div bx
  3274.             xchg bx,ax
  3275.  
  3276.             mov al,0B6h             ;Set frequency
  3277.             out 43h,al
  3278.             mov al,bl
  3279.             out 42h,al
  3280.             mov al,bh
  3281.             out 42h,al
  3282.  
  3283.             in al,61h               ;Turn on speaker
  3284.             or al,3
  3285.             out 61h,al
  3286.  
  3287.             popa                    ;Restore registers
  3288.             pop bp                  ;Delete stack frame
  3289.             ret 2                   ;Return
  3290.  
  3291. EndP        sound
  3292.  
  3293. ;****************** nosound() -- Turn off speaker
  3294. ;void nosound(void);
  3295.  
  3296. Proc        nosound
  3297.  
  3298.             push ax                 ;Save AX
  3299.  
  3300.             in al,61h               ;Turn off speaker
  3301.             and al,0FCh
  3302.             out 61h,al
  3303.  
  3304.             pop ax                  ;Restore AX
  3305.             ret                     ;Return
  3306.  
  3307. EndP        nosound
  3308.  
  3309. End
  3310.